Làm cách nào để chuyển đổi (hoặc tạo) một lớp singleton biên dịch và hành xử chính xác khi sử dụng tính năng tham chiếu tự động (ARC) trong Xcode 4.2?
Làm cách nào để chuyển đổi (hoặc tạo) một lớp singleton biên dịch và hành xử chính xác khi sử dụng tính năng tham chiếu tự động (ARC) trong Xcode 4.2?
Câu trả lời:
Theo cách chính xác giống như cách mà bạn (nên) đã làm nó:
+ (instancetype)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
static
biến @David được khai báo trong một phương thức / hàm giống như một static
biến được khai báo bên ngoài một phương thức / hàm, chúng chỉ có giá trị trong phạm vi của phương thức / hàm đó. Mỗi lần chạy riêng biệt thông qua +sharedInstance
phương thức (ngay cả trên các luồng khác nhau) sẽ 'thấy' cùng một sharedInstance
biến.
nếu bạn muốn tạo phiên bản khác khi cần thiết. Làm thế này:
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
khác, bạn nên làm điều này:
+ (id)allocWithZone:(NSZone *)zone
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
dispatch_once()
Bit có nghĩa là bạn sẽ không nhận được các trường hợp bổ sung, ngay cả trong ví dụ đầu tiên ...?
[[MyClass alloc] init]
và bỏ qua sharedInstance
quyền truy cập. DongXu, bạn nên xem bài viết Singleton của Peter Hosey . Nếu bạn định ghi đè allocWithZone:
để ngăn không cho nhiều phiên bản được tạo, bạn cũng nên ghi đè init
để ngăn phiên bản được chia sẻ lại được khởi tạo lại.
allocWithZone:
phiên bản. Cám ơn.
Đây là phiên bản dành cho ARC và không ARC
Cách sử dụng:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
Đây là mô hình của tôi dưới ARC. Đáp ứng mẫu mới bằng GCD và cũng thỏa mãn mẫu ngăn chặn khởi tạo cũ của Apple.
@implementation AAA
+ (id)alloc
{
return [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
abort();
}
+ (instancetype)theController
{
static AAA* c1 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
c1 = [[super allocWithZone:nil] init];
// For confirm...
NSLog(@"%@", NSStringFromClass([c1 class])); // Prints AAA
NSLog(@"%@", @([c1 class] == self)); // Prints 1
Class real_superclass_obj = class_getSuperclass(self);
NSLog(@"%@", @(real_superclass_obj == self)); // Prints 0
});
return c1;
}
@end
c1
là một ví dụ của AAA
siêu lớp không? Bạn cần phải gọi +alloc
về self
, không phải trên super
.
super
không có nghĩa là đối tượng siêu hạng. Bạn không thể có được đối tượng siêu hạng Nó chỉ có nghĩa là định tuyến các thông điệp đến phiên bản siêu hạng của phương thức. super
vẫn còn điểm self
lớp. Nếu bạn muốn có được đối tượng siêu hạng, bạn cần có các hàm phản chiếu thời gian chạy.
-allocWithZone:
phương thức chỉ là một chuỗi đơn giản cho chức năng phân bổ của thời gian chạy để cung cấp điểm ghi đè. Vì vậy, cuối cùng, self
con trỏ == đối tượng lớp hiện tại sẽ được chuyển đến bộ cấp phát và cuối cùng AAA
cá thể sẽ được phân bổ.
super
việc trong các phương thức của lớp.
Đọc câu trả lời này và sau đó đi và đọc câu trả lời khác.
Trước tiên, bạn phải biết Singleton nghĩa là gì và yêu cầu của nó là gì, nếu bạn không hiểu nó, hơn là bạn sẽ không hiểu giải pháp - tất cả!
Để tạo Singleton thành công, bạn phải có thể thực hiện 3 thao tác sau:
dispatch_once_t
giúp bạn giải quyết tình trạng cuộc đua bằng cách chỉ cho phép khối của nó được gửi đi một lần.
Static
giúp bạn ghi nhớ giá trị của nó qua bất kỳ số lượng yêu cầu nào. Làm thế nào để nó nhớ? Nó không cho phép bất kỳ trường hợp mới nào có tên chính xác của sharedInstance của bạn được tạo lại, nó chỉ hoạt động với cái được tạo ban đầu.
Không sử dụng gọi điện alloc
init
(nghĩa là chúng ta vẫn có alloc
init
các phương thức vì chúng ta là lớp con NSObject, mặc dù chúng ta KHÔNG nên sử dụng chúng) trên lớp sharedInstance của mình, chúng ta đạt được điều này bằng cách sử dụng +(instancetype)sharedInstance
, được giới hạn chỉ được bắt đầu một lần , bất kể nhiều lần thử từ các luồng khác nhau đồng thời và ghi nhớ giá trị của nó.
Một số Singletons hệ thống phổ biến nhất đi kèm với chính ca cao là:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Về cơ bản, bất cứ điều gì cần có hiệu ứng tập trung sẽ cần phải tuân theo một số kiểu mẫu thiết kế Singleton.
Ngoài ra, Objective-C cung cấp phương thức khởi tạo + (void) cho NSObject và tất cả các lớp con của nó. Nó luôn được gọi trước bất kỳ phương thức nào của lớp.
Tôi đã đặt một điểm dừng một lần trong iOS 6 và Clark_once xuất hiện trong các khung stack.
Lớp đơn: Không ai có thể tạo nhiều hơn một đối tượng của lớp trong mọi trường hợp hoặc thông qua bất kỳ cách nào.
+ (instancetype)sharedInstance
{
static ClassName *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ClassName alloc] init];
// Perform other initialisation...
});
return sharedInstance;
}
// You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only.
-(MyClass)init
{
return [ClassName sharedInstance];
}
Có hai vấn đề với câu trả lời được chấp nhận, có thể có hoặc không có liên quan cho mục đích của bạn.
Đoạn mã sau giải quyết cả hai vấn đề sau:
+ (instancetype)sharedInstance {
static id mutex = nil;
static NSMutableDictionary *instances = nil;
//Initialize the mutex and instances dictionary in a thread safe manner
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mutex = [NSObject new];
instances = [NSMutableDictionary new];
});
id instance = nil;
//Now synchronize on the mutex
//Note: do not synchronize on self, since self may differ depending on which class this method is called on
@synchronized(mutex) {
id <NSCopying> key = (id <NSCopying>)self;
instance = instances[key];
if (instance == nil) {
//Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
id allocatedInstance = [self alloc];
//Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
//Do this right after allocation to avoid the stackoverflow problem
if (allocatedInstance != nil) {
instances[key] = allocatedInstance;
}
instance = [allocatedInstance init];
//Following code may be overly cautious
if (instance != allocatedInstance) {
//Somehow the init method did not return the same instance as the alloc method
if (instance == nil) {
//If init returns nil: immediately remove the instance again
[instances removeObjectForKey:key];
} else {
//Else: put the instance in the dictionary instead of the allocatedInstance
instances[key] = instance;
}
}
}
}
return instance;
}
#import <Foundation/Foundation.h>
@interface SingleTon : NSObject
@property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;
@end
#import "SingleTon.h"
@implementation SingleTon
+(SingleTon *) theSingleTon{
static SingleTon *theSingleTon = nil;
if (!theSingleTon) {
theSingleTon = [[super allocWithZone:nil] init
];
}
return theSingleTon;
}
+(id)allocWithZone:(struct _NSZone *)zone{
return [self theSingleTon];
}
-(id)init{
self = [super init];
if (self) {
// Set Variables
_name = @"Kiran";
}
return self;
}
@end
Hy vọng mã trên sẽ giúp nó ra.
nếu bạn cần tạo singleton nhanh chóng,
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
hoặc là
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
bạn có thể sử dụng cách này
let sharedClass = LibraryAPI.sharedInstance