ฉันจะแปลง (หรือสร้าง) คลาสซิงเกิลตันที่รวบรวมและทำงานอย่างถูกต้องเมื่อใช้การนับการอ้างอิงอัตโนมัติ (ARC) ใน Xcode 4.2 ได้อย่างไร
ฉันจะแปลง (หรือสร้าง) คลาสซิงเกิลตันที่รวบรวมและทำงานอย่างถูกต้องเมื่อใช้การนับการอ้างอิงอัตโนมัติ (ARC) ใน Xcode 4.2 ได้อย่างไร
คำตอบ:
ในลักษณะเดียวกับที่คุณ (ควร) ทำมาแล้ว:
+ (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
ตัวแปร@David ที่ประกาศภายในเมธอด / ฟังก์ชั่นจะเหมือนกับstatic
ตัวแปรที่ประกาศภายนอกเมธอด / ฟังก์ชั่นโดยจะใช้ได้ภายในขอบเขตของเมธอด / ฟังก์ชันนั้นเท่านั้น ทุกการทำงานที่แยกกันด้วย+sharedInstance
วิธีการ (แม้จะอยู่ในเธรดที่ต่างกัน) จะ 'เห็น' sharedInstance
ตัวแปรเดียวกัน
ถ้าคุณต้องการสร้างอินสแตนซ์อื่น ๆ ตามต้องการทำสิ่งนี้:
+ (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;
}
มิฉะนั้นคุณควรทำสิ่งนี้:
+ (id)allocWithZone:(NSZone *)zone
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
dispatch_once()
บิตหมายความว่าคุณจะไม่ได้รับอินสแตนซ์เพิ่มเติมแม้แต่ในตัวอย่างแรก ... ?
[[MyClass alloc] init]
และข้ามการsharedInstance
เข้าถึง Dongxu, คุณควรดูที่บทความซิงเกิล Peter Hosey ของ หากคุณกำลังจะแทนที่allocWithZone:
เพื่อป้องกันการสร้างอินสแตนซ์เพิ่มเติมคุณควรแทนที่init
เพื่อป้องกันไม่ให้อินสแตนซ์ที่แชร์ถูกเริ่มต้นใหม่
allocWithZone:
รุ่น ขอบคุณ.
นี่เป็นรุ่นสำหรับ ARC และไม่ใช่ ARC
วิธีใช้:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
นี่คือรูปแบบของฉันภายใต้ ARC ตอบสนองรูปแบบใหม่ด้วย GCD และยังเป็นไปตามรูปแบบการป้องกันอินสแตนซ์เก่าของ 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
เป็นตัวอย่างของAAA
ซูเปอร์คลาสหรือไม่? คุณจะต้องเรียก+alloc
บนไม่ได้อยู่ในself
super
super
ไม่ได้หมายถึงวัตถุระดับซุปเปอร์ คุณไม่สามารถรับออบเจ็กต์ระดับสูงได้มันหมายถึงการกำหนดเส้นทางข้อความไปยังเมธอดเวอร์ชันซุปเปอร์คลาส super
ยังคงชี้self
ระดับ หากคุณต้องการได้รับออบเจ็กต์ระดับสูงคุณจะต้องได้รับฟังก์ชั่นการสะท้อนแบบรันไทม์
-allocWithZone:
เมธอดเป็นเพียงเชนการทำงานของการจัดสรรรันไทม์เพื่อเสนอจุดที่สำคัญ ดังนั้นในที่สุดself
ตัวชี้ == วัตถุคลาสปัจจุบันจะถูกส่งผ่านไปยังตัวจัดสรรและในที่สุดAAA
อินสแตนซ์จะถูกจัดสรร
super
ทำงานในวิธีการเรียน
อ่านคำตอบนี้แล้วไปอ่านคำตอบอื่น
ก่อนอื่นคุณต้องรู้ว่า Singleton มีความหมายว่าอะไรและมีข้อกำหนดอะไรบ้างถ้าคุณไม่เข้าใจมันมากกว่าที่คุณจะไม่เข้าใจวิธีแก้ปัญหา - เลย!
ในการสร้าง Singleton สำเร็จคุณต้องทำสิ่งต่อไปนี้ 3:
dispatch_once_t
ช่วยคุณแก้ปัญหาสภาพการแข่งขันโดยอนุญาตให้ส่งบล็อกของมันเพียงครั้งเดียว
Static
ช่วยให้คุณ“ จดจำ” คุณค่าของมันในจำนวนการเรียกใช้ใด ๆ จำได้อย่างไร ไม่อนุญาตให้มีอินสแตนซ์ใหม่ที่มีชื่อที่แน่นอนของ sharedInstance ของคุณถูกสร้างขึ้นอีกครั้งเพียงแค่ทำงานกับอินสแตนซ์ที่สร้างขึ้น แต่เดิม
ไม่ใช้การโทรalloc
init
(เช่นเรายังมีalloc
init
วิธีการเนื่องจากเราเป็น subclass ของ NSObject ถึงแม้ว่าเราไม่ควรใช้มัน) ในคลาส sharedInstance ของเราเราทำได้โดยการใช้+(instancetype)sharedInstance
ซึ่งถูก จำกัด ขอบเขตให้เริ่มต้นเพียงครั้งเดียวโดยไม่คำนึงถึงความพยายามจากหลายเธรด ในเวลาเดียวกันและจดจำค่าของมัน
ระบบ Singletons ที่พบมากที่สุดที่มาพร้อมกับโกโก้คือ:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
โดยทั่วไปอะไรก็ตามที่จะต้องมีผลกระทบจากศูนย์กลางจะต้องเป็นไปตามรูปแบบการออกแบบซิงเกิล
อีกวิธีหนึ่งคือ Objective-C จัดเตรียมวิธีการเริ่มต้น + (void) สำหรับ NSObject และคลาสย่อยทั้งหมด มันถูกเรียกเสมอก่อนวิธีการใด ๆ ของชั้นเรียน
ฉันตั้งค่าเบรกพอยต์ในหนึ่งครั้งใน iOS 6 และ dispatch_once ปรากฏขึ้นในเฟรมสแต็ก
Singleton Class: ไม่มีใครสามารถสร้างวัตถุมากกว่าหนึ่งคลาสในทุกกรณีหรือทุกทาง
+ (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];
}
มีสองประเด็นเกี่ยวกับคำตอบที่ยอมรับซึ่งอาจหรืออาจไม่เกี่ยวข้องกับวัตถุประสงค์ของคุณ
รหัสต่อไปนี้จะดูแลปัญหาทั้งสองนี้:
+ (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
หวังว่ารหัสข้างต้นจะช่วยมันออกมา
ถ้าคุณต้องการสร้างซิงเกิลตันอย่างรวดเร็ว
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
หรือ
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
คุณสามารถใช้วิธีนี้
let sharedClass = LibraryAPI.sharedInstance