답변:
문제 설명 :
하나의 대안 :
Objective-C 기능을 사용하여 클래스 변수 동작 시뮬레이션
classA.m 내에서 정적 변수를 선언 / 정의하면 classA 메소드 (및 classA.m에 넣은 모든 것)에 대해서만 액세스 할 수 있습니다.
NSObject 초기화 클래스 메소드를 덮어 써서 정적 변수를 ClassB 인스턴스로 한 번만 초기화하십시오.
왜 NSObject initialize 메소드를 덮어 써야하는지 궁금 할 것입니다. 이 방법에 대한 Apple 문서는 다음과 같은 대답을 가지고 있습니다. "런타임은 클래스 바로 직전에 프로그램의 각 클래스에 초기화를 보내거나 클래스에서 상속 된 모든 클래스는 프로그램 내에서 첫 번째 메시지를 보냅니다. 클래스를 사용하지 않으면 호출 될 수 없습니다.) ".
모든 ClassA 클래스 / 인스턴스 메소드 내에서 정적 변수를 사용하십시오.
코드 샘플 :
파일 : 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
참고 문헌 :
initialize
는 각 클래스 (하위 클래스 앞의 슈퍼 클래스)에 대해 한 번 호출되지만 서브 클래스가 재정의하지 않으면 initialize
부모 클래스 initialize
가 다시 호출됩니다. 따라서 해당 코드를 두 번 실행하지 않으려면 가드가 필요합니다. Apple의 Objective-C 문서에서 클래스 객체 초기화를 참조하십시오 .
Xcode 8부터 Obj-C에서 클래스 속성을 정의 할 수 있습니다. 이것은 Swift의 정적 속성과 상호 운용되도록 추가되었습니다.
Objective-C는 이제 Swift 유형 특성과 상호 운용되는 클래스 특성을 지원합니다. @property (클래스) NSString * someStringProperty;로 선언됩니다. 그들은 결코 합성되지 않습니다. (23891898)
여기에 예가 있습니다
@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
그런 다음 다음과 같이 액세스 할 수 있습니다.
YourClass.currentId = 1;
val = YourClass.currentId;
다음은 이 오래된 답변을 편집하기 위해 참조로 사용한 매우 흥미로운 설명 게시물 입니다.
2011 답변 : (이것을 사용하지 마십시오, 끔찍합니다)
정말로 전역 변수를 선언하고 싶지 않다면 또 다른 옵션이있을 수 있습니다. 정통은 아니지만 :-) 작동합니다 ... 정적 변수를 사용하여 이와 같은 "get & set"메소드를 선언 할 수 있습니다.
+ (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;
}
따라서 값을 얻으려면 다음을 호출하십시오.
NSString *testVal = [MyClass testHolder:nil]
그런 다음 설정하려는 경우 :
[MyClass testHolder:testVal]
이 의사 정적 변수를 nil로 설정하려는 경우 다음 testHolder
과 같이 선언 할 수 있습니다 .
+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
static NSString *test;
if(shouldSet) {
if(test != nil)
[test release];
test = [_test retain];
}
return test;
}
그리고 두 가지 편리한 방법 :
+ (NSString*)test {
return [MyClass testHolderSet:NO newValue:nil];
}
+ (void)setTest:(NSString*)_test {
[MyClass testHolderSet:YES newValue:_test];
}
그것이 도움이되기를 바랍니다! 행운을 빕니다.
.m
파일 에서 액세스 할 수 없기 때문에 실제로는 전역 변수가 아니며 파일 내에서 "전역"인 것이 Class.m
좋습니다.
.m 파일에서 파일 전역 변수를 선언하십시오.
static int currentID = 1;
그런 다음 init 루틴에서 다음을 참조하십시오.
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
또는 다른 시간에 변경해야하는 경우 (예 : openConnection 메소드에서) 증가 시키십시오. 스레딩 문제가 발생할 수있는 경우 스레드 안전 상태가 아니므로 동기화를 수행해야합니다 (또는 원자 추가 기능을 사용해야 함).
(엄격히 말하면 질문에 대한 대답은 아니지만 클래스 변수를 찾을 때 내 경험에 유용 할 것입니다)
클래스 메소드는 클래스 변수가 다른 언어로 수행하는 많은 역할을 수행 할 수 있습니다 (예 : 테스트 중에 구성 변경).
@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
이제 클래스의 객체는를 MyCls
호출 Resource:changeSomething:
할 때 문자열 @"Something general"
을 호출 doTheThing:
하지만 문자열 을 통해 파생 된 객체를 호출 MySpecialCase
합니다 @"Something specific"
.
또 다른 가능성은 작은 NSNumber
서브 클래스 싱글 톤 을 갖는 것 입니다.