อันดับแรกใช่นี่เป็นโซลูชันที่ปลอดภัยสำหรับเธรด dispatch_once
รูปแบบนี้เป็นวิธีที่ทันสมัยและปลอดภัยในการสร้างซิงเกิลตันใน Objective-C ไม่ต้องกังวล
คุณถามว่านี่เป็นวิธีที่ "ดีที่สุด" หรือไม่ หนึ่งควรยอมรับว่าinstancetype
และ[[self alloc] init]
อาจทำให้เข้าใจผิดเมื่อใช้ร่วมกับซิงเกิล
ประโยชน์ของการinstancetype
เป็นว่ามันเป็นวิธีที่ชัดเจนในการประกาศว่าชั้นสามารถ subclassed โดยไม่ต้องหันไปประเภทของid
เช่นที่เราต้องทำในปีกลาย
แต่static
วิธีการนี้นำเสนอความท้าทายระดับคลาสย่อย เกิดอะไรขึ้นถ้าImageCache
และBlobCache
singletons ทั้งสอง subclasses จากCache
superclass โดยไม่ต้องดำเนินการของตัวเอง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
จากนั้นคุณสามารถไปข้างหน้าและเขียนทะเยอทะยานสำหรับคุณสมบัตินี้ (การใช้งานจะใช้dispatch_once
รูปแบบที่คุณแนะนำ):
+ (Foo *)sharedFoo { ... }
ประโยชน์ของสิ่งนี้คือถ้าผู้ใช้ Swift ใช้งานพวกเขาจะทำสิ่งที่ชอบ:
let foo = Foo.shared
หมายเหตุไม่มี()
เนื่องจากเราใช้มันเป็นทรัพย์สิน เริ่มต้น Swift 3 นี่คือวิธีการเข้าถึงซิงเกิลโดยทั่วไป ดังนั้นการกำหนดเป็นคุณสมบัติช่วยอำนวยความสะดวกในการทำงานร่วมกัน
นอกจากนี้ถ้าคุณดูว่า Apple นิยามซิงเกิลตันของพวกเขาอย่างไรนี่คือรูปแบบที่พวกเขานำมาใช้เช่นการNSURLSession
กำหนดซิงเกิลดังต่อไปนี้:
@property (class, readonly, strong) NSURLSession *sharedSession;
การพิจารณาการใช้งานร่วมกันของ Swift ที่น้อยมากคือชื่อของซิงเกิล sharedInstance
มันเป็นเรื่องที่ดีที่สุดถ้าคุณสามารถรวมชื่อประเภทที่มากกว่า ตัวอย่างเช่นถ้าชั้นเป็นคุณอาจกำหนดเดี่ยวทรัพย์สินFoo
sharedFoo
หรือถ้าชั้นเป็นคุณอาจเรียกทรัพย์สินDatabaseManager
sharedManager
จากนั้นผู้ใช้ Swift สามารถทำได้:
let foo = Foo.shared
let manager = DatabaseManager.shared
เห็นได้ชัดว่าถ้าคุณต้องการใช้จริงๆsharedInstance
คุณสามารถประกาศชื่อ Swift ได้ทุกเมื่อที่คุณต้องการ:
@property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);
เห็นได้ชัดว่าเมื่อเขียนรหัส Objective-C เราไม่ควรปล่อยให้การทำงานร่วมกันของ Swift มีมากกว่าข้อควรพิจารณาด้านการออกแบบอื่น ๆ แต่ถึงกระนั้นถ้าเราสามารถเขียนโค้ดที่รองรับทั้งสองภาษาได้อย่างสวยงาม
ผมเห็นด้วยกับคนอื่น ๆ ที่ชี้ให้เห็นว่าถ้าคุณอยากให้เรื่องนี้เป็นซิงเกิลจริงที่นักพัฒนาไม่สามารถ / ไม่ควร (ตั้งใจ) ยกตัวอย่างกรณีของตัวเองunavailable
รอบคัดเลือกในinit
และnew
ระมัดระวัง