iOS 4.0 이상을 타겟팅 할 수있는 경우
GCD를 사용하면 Objective-C (스레드 안전)에서 싱글 톤을 만드는 가장 좋은 방법입니까?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
답변
이것은 클래스의 인스턴스를 만드는 완벽하고 수용 가능한 스레드 안전 방법입니다. 기술적으로 “단일”이 아닐 수도 있지만 (이러한 개체 중 하나만있을 수 있음) 개체 [Foo sharedFoo]
에 액세스하는 방법 만 사용하면 충분합니다.
답변
인스턴스 유형
instancetype
에 대한 많은 언어 확장 중 하나입니다 Objective-C
새로운 릴리스마다 추가됩니다.
그것을 알고 사랑하십시오.
또한 하위 수준의 세부 사항에주의를 기울이면 Objective-C를 변환하는 강력하고 새로운 방법에 대한 통찰력을 얻을 수있는 방법을 예로 들어 보겠습니다.
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^
{
sharedInstance = [self new];
});
return sharedInstance;
}
+ (Class*)sharedInstance
{
static dispatch_once_t once;
static Class *sharedInstance;
dispatch_once(&once, ^
{
sharedInstance = [self new];
});
return sharedInstance;
}
답변
MySingleton.h
@interface MySingleton : NSObject
+(instancetype)sharedInstance;
+(instancetype)alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype)init __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype)new __attribute__((unavailable("new not available, call sharedInstance instead")));
-(instancetype)copy __attribute__((unavailable("copy not available, call sharedInstance instead")));
@end
MySingleton.m
@implementation MySingleton
+(instancetype)sharedInstance {
static dispatch_once_t pred;
static id shared = nil;
dispatch_once(&pred, ^{
shared = [[super alloc] initUniqueInstance];
});
return shared;
}
-(instancetype)initUniqueInstance {
return [super init];
}
@end
답변
alloc 메소드를 겹쳐 쓰면서 클래스를 할당하지 않도록 할 수 있습니다.
@implementation MyClass
static BOOL useinside = NO;
static id _sharedObject = nil;
+(id) alloc {
if (!useinside) {
@throw [NSException exceptionWithName:@"Singleton Vialotaion" reason:@"You are violating the singleton class usage. Please call +sharedInstance method" userInfo:nil];
}
else {
return [super alloc];
}
}
+(id)sharedInstance
{
static dispatch_once_t p = 0;
dispatch_once(&p, ^{
useinside = YES;
_sharedObject = [[MyClass alloc] init];
useinside = NO;
});
// returns the same object each time
return _sharedObject;
}
답변
Dave는 정확합니다. 완벽합니다. 당신은 체크 아웃 할 수 있습니다 싱글 만드는 방법에 대한 애플의 워드 프로세서 클래스는 sharedFoo 방법을 사용하지 않을 경우에만 하나를 창조 할 수 있는지 확인하기 위해 다른 방법의 일부를 구현하는 방법에 대한 팁을.
답변
[[MyClass alloc] init]이 sharedInstance와 동일한 객체를 반환하도록하려면 (필자의 의견으로는 필요하지 않지만 일부 사람들은 원하는 경우) 두 번째 dispatch_once를 사용하여 매우 쉽고 안전하게 수행 할 수 있습니다.
- (instancetype)init
{
static dispatch_once_t once;
static Class *sharedInstance;
dispatch_once(&once, ^
{
// Your normal init code goes here.
sharedInstance = self;
});
return sharedInstance;
}
이것은 [[MyClass alloc] init]와 [MyClass sharedInstance]의 조합이 동일한 객체를 반환 할 수있게합니다. [MyClass sharedInstance]는 조금 더 효율적입니다. 작동 방식 : [MyClass sharedInstance]는 [[MyClass alloc] init]를 한 번 호출합니다. 다른 코드에서도 여러 번 호출 할 수 있습니다. init의 첫 번째 호출자는 “정상적인”초기화를 수행하고 싱글 톤 객체를 init 메소드에 저장합니다. 나중에 init을 호출하면 alloc이 리턴 한 내용을 완전히 무시하고 동일한 sharedInstance를 리턴합니다. alloc의 결과는 할당 해제됩니다.
+ sharedInstance 메소드는 항상 그렇듯이 작동합니다. [[MyClass alloc] init]를 호출 한 첫 번째 호출자가 아닌 경우 init의 결과는 alloc 호출의 결과가 아니지만 괜찮습니다.
답변
이것이 “싱글 톤을 만드는 가장 좋은 방법”인지 묻습니다.
몇 가지 생각 :
-
첫째, 이것은 스레드 안전 솔루션입니다. 이
dispatch_once
패턴은 Objective-C에서 싱글 톤을 생성하는 현대적이고 안전한 스레드 방식입니다. 걱정하지 마십시오. -
그러나 이것이 최선의 방법인지 물었다. 그러나 싱글 톤과 함께 사용 하면
instancetype
및[[self alloc] init]
오해의 가능성 이 있음을 인정해야합니다 .instancetype
그것의 장점은id
우리가 어제 해왔 던 것처럼 유형에 의지하지 않고 클래스를 서브 클래 싱 할 수 있음을 선언하는 명백한 방법이라는 것입니다 .그러나이
static
방법에서는 서브 클래 싱 문제를 제시합니다. 자체 메소드 를 구현하지 않고 수퍼 클래스의 서브 클래스 인 경우ImageCache
와BlobCache
싱글 톤은 어떻습니까?Cache
sharedCache
ImageCache *imageCache = [ImageCache sharedCache]; // fine BlobCache *blobCache = [BlobCache sharedCache]; // error; this will return the aforementioned ImageCache!!!
이것이 작동하기 위해서는 서브 클래스가 자신 만의
sharedInstance
(또는 특정 클래스에 대해 호출하는) 메소드를 구현해야 합니다.결론적으로, 원본
sharedInstance
은 하위 클래스를 지원하는 것처럼 보이지만 그렇지 않습니다. 서브 클래 싱을 지원하려는 경우 최소한 미래 개발자에게이 방법을 재정의해야한다고 경고하는 설명서가 포함되어야합니다. -
Swift와의 최상의 상호 운용성을 위해 클래스 메소드가 아닌 속성으로 정의하려는 경우가 있습니다. 예 :
@interface Foo : NSObject @property (class, readonly, strong) Foo *sharedFoo; @end
그런 다음이 속성에 대한 getter를 작성할 수 있습니다 (구현은
dispatch_once
제안한 패턴을 사용합니다 ).+ (Foo *)sharedFoo { ... }
이것의 장점은 Swift 사용자가 그것을 사용하면 다음과 같이 할 수 있다는 것입니다.
let foo = Foo.shared
()
속성으로 구현했기 때문에 는 없습니다 . Swift 3부터는 싱글 톤에 일반적으로 액세스하는 방법이 있습니다. 따라서 속성으로 정의하면 상호 운용성을 촉진하는 데 도움이됩니다.따로, Apple이 싱글 톤을 정의하는 방법을 살펴보면, 이것이 싱글턴을 정의한 패턴입니다. 예를 들어
NSURLSession
싱글 톤은 다음과 같이 정의됩니다.@property (class, readonly, strong) NSURLSession *sharedSession;
-
매우 작은 스위프트 상호 운용성 고려 사항은 싱글 톤의 이름이었습니다. 유형이 아닌 이름을 통합 할 수있는 것이 가장 좋습니다
sharedInstance
. 예를 들어 클래스가Foo
인 경우 singleton 속성을로 정의 할 수 있습니다sharedFoo
. 또는 클래스가 있으면DatabaseManager
속성을 호출 할 수 있습니다sharedManager
. 그런 다음 Swift 사용자는 다음을 수행 할 수 있습니다.let foo = Foo.shared let manager = DatabaseManager.shared
분명히을 사용하려는 경우 언제든지 원하는
sharedInstance
스위프트 이름을 선언 할 수 있습니다.@property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);
분명히 Objective-C 코드를 작성할 때 Swift 상호 운용성이 다른 디자인 고려 사항보다 중요하지는 않지만 두 언어를 정상적으로 지원하는 코드를 작성할 수 있다면 바람직합니다.
-
나는 당신이 원하는 경우,이 개발자가 / (실수로) 자신의 인스턴스의 인스턴스를 안 할 수없는 진정한 싱글로 지적 다른 사람과 동의
unavailable
에 관한 규정init
하고new
신중한이다.