อาจจะชัดเจน แต่ฉันไม่รู้วิธีประกาศคุณสมบัติของคลาสใน Objective-C
ฉันต้องการแคชพจนานุกรมต่อชั้นเรียนและสงสัยว่าจะใส่ไว้ในชั้นเรียนได้อย่างไร
อาจจะชัดเจน แต่ฉันไม่รู้วิธีประกาศคุณสมบัติของคลาสใน Objective-C
ฉันต้องการแคชพจนานุกรมต่อชั้นเรียนและสงสัยว่าจะใส่ไว้ในชั้นเรียนได้อย่างไร
คำตอบ:
คุณสมบัติมีความหมายเฉพาะใน Objective-C แต่ฉันคิดว่าคุณหมายถึงสิ่งที่เทียบเท่ากับตัวแปรสแตติก? เช่นมีเพียงอินสแตนซ์เดียวสำหรับ Foo ทุกประเภท
ในการประกาศฟังก์ชันคลาสใน Objective-C คุณใช้เครื่องหมาย + แทน - ดังนั้นการนำไปใช้ของคุณจะมีลักษณะดังนี้:
// Foo.h
@interface Foo {
}
+ (NSDictionary *)dictionary;
// Foo.m
+ (NSDictionary *)dictionary {
static NSDictionary *fooDict = nil;
if (fooDict == nil) {
// create dict
}
return fooDict;
}
.
ไวยากรณ์ -accessor ไม่เชื่อมโยงกับคุณสมบัติใน Objective-C, มันเป็นเพียงแค่รวบรวมในทางลัดสำหรับวิธีการใด ๆ ที่ผลตอบแทนบางสิ่งบางอย่างโดยไม่ต้องสละ args ใด ๆ ในกรณีนี้ผมต้องการทีผมเองชอบ.
ไวยากรณ์สำหรับการใช้งานใด ๆ ที่รหัสลูกค้าตั้งใจที่จะได้รับสิ่งที่ไม่ดำเนินการ(แม้ว่ารหัสการดำเนินการอาจจะสร้างบางสิ่งบางอย่างในครั้งเดียวหรือดำเนินการผลข้างเคียง) .
ไวยากรณ์การใช้งานจำนวนมากยังส่งผลให้รหัสอ่านง่ายขึ้น: การมีอยู่ของ[…]
s หมายถึงสิ่งที่สำคัญที่จะทำเมื่อดึงใช้.
ไวยากรณ์แทน
ฉันใช้โซลูชันนี้:
@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end
@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end
และฉันพบว่ามันมีประโยชน์อย่างมากในการแทนที่รูปแบบซิงเกิล
หากต้องการใช้งานเพียงเข้าถึงข้อมูลของคุณด้วยเครื่องหมายจุด:
Model.value = 1;
NSLog(@"%d = value", Model.value);
self
หมายอย่างไรในวิธีการเรียน?
@synchronized
?
ดังที่เห็นใน WWDC 2016 / XCode 8 (มีอะไรใหม่ในเซสชัน LLVM @ 5: 05) คุณสมบัติคลาสสามารถประกาศได้ดังนี้
@interface MyType : NSObject
@property (class) NSString *someString;
@end
NSLog(@"format string %@", MyType.someString);
โปรดทราบว่าคุณสมบัติของคลาสจะไม่ถูกสังเคราะห์
@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
static
ตัวแปร( ) ต้องยังคงถูกประกาศและใช้งานและวิธีการใช้งานอย่างชัดเจนเช่นเดียวกับที่เคยเป็นมาก่อนหน้านี้ ไวยากรณ์ Dot นั้นใช้งานได้ก่อนหน้านี้เช่นกัน ในทุกเรื่องนี้ดูเหมือนจะเป็นเรื่องใหญ่กว่าที่เป็นจริง
หากคุณกำลังมองหาระดับเทียบเท่าระดับของ@property
คำตอบคือ "ไม่มีสิ่งนั้น" แต่จำไว้ว่า@property
มันเป็นเพียงวากยสัมพันธ์เท่านั้น มันเพิ่งสร้างวิธีการวัตถุที่ตั้งชื่ออย่างเหมาะสม
คุณต้องการสร้างวิธีการเรียนที่เข้าถึงตัวแปรคงที่ซึ่งตามที่คนอื่นได้กล่าวว่ามีเพียงไวยากรณ์ที่แตกต่างกันเล็กน้อย
UIDevice.currentDevice.identifierForVendor
ทำงานได้สำหรับฉัน
นี่เป็นวิธีที่ปลอดภัยในการทำเธรด:
// Foo.h
@interface Foo {
}
+(NSDictionary*) dictionary;
// Foo.m
+(NSDictionary*) dictionary
{
static NSDictionary* fooDict = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
// create dict
});
return fooDict;
}
การแก้ไขเหล่านี้ทำให้มั่นใจได้ว่า fooDict จะสร้างเพียงครั้งเดียว
จากเอกสารของ Apple : "dispatch_once - เรียกใช้งานวัตถุบล็อกเพียงครั้งเดียวเท่านั้นตลอดอายุการใช้งานของแอปพลิเคชัน"
Initializer element is not a compile-time constant
ความพยายามที่จะเริ่มต้นในพจนานุกรมในบรรทัดเดียวกันเป็นการประกาศคงที่อัตราผลตอบแทนรวบรวมข้อผิดพลาดต่อไปนี้:
ในฐานะของ Xcode 8 Objective-C ตอนนี้รองรับคุณสมบัติคลาส:
@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end
เนื่องจากคุณสมบัติของคลาสจะไม่ถูกสังเคราะห์คุณต้องเขียนการใช้งานของคุณเอง
@implementation MyClass
static NSUUID*_identifier = nil;
+ (NSUUID *)identifier {
if (_identifier == nil) {
_identifier = [[NSUUID alloc] init];
}
return _identifier;
}
@end
คุณเข้าถึงคุณสมบัติคลาสโดยใช้ไวยากรณ์จุดปกติบนชื่อคลาส:
MyClass.identifier;
คุณสมบัติมีค่าเฉพาะในวัตถุไม่ใช่คลาส
ถ้าคุณต้องการเก็บบางสิ่งบางอย่างสำหรับวัตถุทั้งหมดของคลาสคุณต้องใช้ตัวแปรส่วนกลาง คุณสามารถซ่อนมันได้โดยประกาศstatic
ในไฟล์การนำไปใช้งาน
คุณอาจพิจารณาใช้ความสัมพันธ์เฉพาะระหว่างวัตถุของคุณ: คุณกำหนดบทบาทของต้นแบบให้กับวัตถุเฉพาะของคลาสของคุณและเชื่อมโยงวัตถุอื่น ๆ กับต้นแบบนี้ ต้นแบบจะถือพจนานุกรมเป็นคุณสมบัติที่ง่าย ฉันคิดว่าต้นไม้เหมือนต้นไม้ที่ใช้สำหรับลำดับชั้นการดูในแอปพลิเคชัน Cocoa
อีกทางเลือกหนึ่งคือการสร้างวัตถุของคลาสเฉพาะที่ประกอบด้วยทั้งพจนานุกรม 'คลาส' ของคุณและชุดของวัตถุทั้งหมดที่เกี่ยวข้องกับพจนานุกรมนี้ นี่คือสิ่งที่NSAutoreleasePool
ในโกโก้
เริ่มต้นจาก Xcode 8 คุณสามารถใช้คุณสมบัติคลาสตามที่ Berbie ตอบ
อย่างไรก็ตามในการนำไปใช้งานคุณต้องกำหนดทั้ง class getter และ setter สำหรับคุณสมบัติ class โดยใช้ตัวแปรแบบสแตติกแทน iVar
Sample.h
@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end
Sample.m
@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
if (_sharedSample==nil) {
[Sample setSharedSample:_sharedSample];
}
return _sharedSample;
}
+ (void)setSharedSample:(Sample *)sample {
_sharedSample = [[Sample alloc]init];
}
@end
หากคุณมีคุณสมบัติระดับชั้นเรียนจำนวนมากรูปแบบซิงเกิลอาจเป็นไปตามลำดับ บางสิ่งเช่นนี้
// Foo.h
@interface Foo
+ (Foo *)singleton;
@property 1 ...
@property 2 ...
@property 3 ...
@end
และ
// Foo.m
#import "Foo.h"
@implementation Foo
static Foo *_singleton = nil;
+ (Foo *)singleton {
if (_singleton == nil) _singleton = [[Foo alloc] init];
return _singleton;
}
@synthesize property1;
@synthesize property2;
@synthesise property3;
@end
ตอนนี้เข้าถึงคุณสมบัติระดับชั้นของคุณดังนี้:
[Foo singleton].property1 = value;
value = [Foo singleton].property2;
dispatch_once
ที่นี่