Câu trả lời:
Mô tả sự cố :
Một thay thế :
Mô phỏng một hành vi biến lớp bằng các tính năng Objective-C
Khai báo / Xác định một biến tĩnh trong classA.m để nó chỉ có thể truy cập được đối với các phương thức classA (và mọi thứ bạn đặt trong classA.m).
Ghi đè phương thức khởi tạo NSObject để khởi tạo chỉ một lần biến tĩnh với một thể hiện của ClassB.
Bạn sẽ tự hỏi, tại sao tôi nên ghi đè lên phương thức khởi tạo NSObject. Tài liệu của Apple về phương thức này có câu trả lời: "Thời gian chạy gửi khởi tạo cho mỗi lớp trong một chương trình chính xác một lần ngay trước lớp hoặc bất kỳ lớp nào kế thừa từ nó, được gửi tin nhắn đầu tiên từ bên trong chương trình. có thể không bao giờ được gọi nếu lớp không được sử dụng.) ".
Vui lòng sử dụng biến tĩnh trong bất kỳ phương thức lớp / thể hiện ClassA nào.
Mẫu mã :
tập tin: classA.m
static ClassB *classVariableName = nil;
@implementation ClassA
...
+(void) initialize
{
if (! classVariableName)
classVariableName = [[ClassB alloc] init];
}
+(void) classMethodName
{
[classVariableName doSomething];
}
-(void) instanceMethodName
{
[classVariableName doSomething];
}
...
@end
Tài liệu tham khảo :
initialize
được gọi một lần cho mỗi lớp (siêu lớp trước lớp con), nhưng nếu một lớp con không ghi đè initialize
, lớp cha initialize
sẽ được gọi lại. Do đó, cần có người bảo vệ nếu bạn không muốn mã đó thực thi hai lần. Xem Khởi tạo một đối tượng lớp trong các tài liệu Objective-C của Apple.
Kể từ Xcode 8, bạn có thể định nghĩa các thuộc tính lớp trong Obj-C. Điều này đã được thêm vào để tương tác với các thuộc tính tĩnh của Swift.
Objective-C hiện hỗ trợ các thuộc tính lớp, tương tác với các thuộc tính loại Swift. Chúng được khai báo là: @property (class) NSString * someStringProperty;. Chúng không bao giờ được tổng hợp. (23891898)
Đây là một ví dụ
@interface YourClass : NSObject
@property (class, nonatomic, assign) NSInteger currentId;
@end
@implementation YourClass
static NSInteger _currentId = 0;
+ (NSInteger)currentId {
return _currentId;
}
+ (void)setCurrentId:(NSInteger)newValue {
_currentId = newValue;
}
@end
Sau đó, bạn có thể truy cập nó như thế này:
YourClass.currentId = 1;
val = YourClass.currentId;
Dưới đây là một bài giải thích rất thú vị mà tôi đã sử dụng làm tài liệu tham khảo để chỉnh sửa câu trả lời cũ này.
2011 Trả lời: (không sử dụng cái này, nó rất tệ)
Nếu bạn thực sự không muốn khai báo một biến toàn cục, thì có một tùy chọn khác, có thể không chính thống lắm :-), nhưng hoạt động ... Bạn có thể khai báo một phương thức "get & set" như thế này, với một biến tĩnh bên trong:
+ (NSString*)testHolder:(NSString*)_test {
static NSString *test;
if(_test != nil) {
if(test != nil)
[test release];
test = [_test retain];
}
// if(test == nil)
// test = @"Initialize the var here if you need to";
return test;
}
Vì vậy, nếu bạn cần lấy giá trị, chỉ cần gọi:
NSString *testVal = [MyClass testHolder:nil]
Và sau đó, khi bạn muốn đặt nó:
[MyClass testHolder:testVal]
Trong trường hợp bạn muốn có thể đặt pseudo-static-var này thành nil, bạn có thể khai báo testHolder
như sau:
+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
static NSString *test;
if(shouldSet) {
if(test != nil)
[test release];
test = [_test retain];
}
return test;
}
Và hai phương pháp tiện dụng:
+ (NSString*)test {
return [MyClass testHolderSet:NO newValue:nil];
}
+ (void)setTest:(NSString*)_test {
[MyClass testHolderSet:YES newValue:_test];
}
Hy vọng nó giúp! Chúc may mắn.
.m
tệp khác và tôi nghĩ rằng nó là "toàn cầu" trong Class.m
tệp.
Trên tệp .m của bạn, bạn có thể khai báo một biến là tĩnh:
static ClassName *variableName = nil;
Sau đó, bạn có thể khởi tạo nó trên +(void)initialize
phương pháp của bạn .
Xin lưu ý rằng đây là biến tĩnh C đơn giản và không tĩnh theo nghĩa Java hoặc C # xem xét nó, nhưng sẽ mang lại kết quả tương tự.
Trong tệp .m của bạn, khai báo một biến toàn cục của tệp:
static int currentID = 1;
sau đó trong thói quen init của bạn, hãy xem lại rằng:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
hoặc nếu nó cần thay đổi vào một thời điểm khác (ví dụ: trong phương thức openConnection của bạn), sau đó tăng nó ở đó. Hãy nhớ rằng nó không phải là luồng an toàn, vì bạn sẽ cần phải thực hiện đồng bộ hóa (hoặc tốt hơn nữa, sử dụng một bổ sung nguyên tử) nếu có thể có bất kỳ vấn đề luồng nào.
Như pgb đã nói, không có "biến lớp", chỉ "biến thể hiện". Cách mục tiêu-c thực hiện các biến lớp là một biến toàn cục tĩnh bên trong tệp .m của lớp. "Tĩnh" đảm bảo rằng biến không thể được sử dụng bên ngoài tệp đó (nghĩa là nó không thể ở bên ngoài).
(Nói đúng ra không phải là một câu trả lời cho câu hỏi, nhưng theo kinh nghiệm của tôi có thể hữu ích khi tìm kiếm các biến lớp)
Một phương thức lớp thường có thể đóng nhiều vai trò mà một biến lớp sẽ làm trong các ngôn ngữ khác (ví dụ: thay đổi cấu hình trong các thử nghiệm):
@interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
@end
@implementation
+ (NSString*)theNameThing { return @"Something general"; }
- (void)doTheThing {
[SomeResource changeSomething:[self.class theNameThing]];
}
@end
@interface MySpecialCase: MyCls
@end
@implementation
+ (NSString*)theNameThing { return @"Something specific"; }
@end
Bây giờ, một đối tượng của các MyCls
cuộc gọi lớp Resource:changeSomething:
với chuỗi @"Something general"
khi có cuộc gọi đến doTheThing:
, nhưng một đối tượng xuất phát từ MySpecialCase
chuỗi @"Something specific"
.
Một khả năng khác là có một NSNumber
lớp đơn nhỏ.