มีวิธีบังคับใช้การพิมพ์บน NSArray, NSMutableArray ฯลฯ หรือไม่?


คำตอบ:


35

คุณสามารถสร้างหมวดหมู่ด้วย-addSomeClass:วิธีการเพื่อให้สามารถตรวจสอบประเภทคงที่เวลาคอมไพล์ได้ (ดังนั้นคอมไพเลอร์จะแจ้งให้คุณทราบหากคุณพยายามเพิ่มวัตถุที่รู้ว่าเป็นคลาสอื่นผ่านวิธีนั้น) แต่ไม่มีวิธีบังคับอย่างแท้จริง อาร์เรย์มีเฉพาะออบเจ็กต์ของคลาสที่กำหนด

โดยทั่วไปดูเหมือนว่าไม่มีความจำเป็นสำหรับข้อ จำกัด ดังกล่าวใน Objective-C ฉันไม่คิดว่าฉันเคยได้ยินโปรแกรมเมอร์ Cocoa ที่มีประสบการณ์ต้องการคุณสมบัตินั้น มีเพียงคนเดียวที่ดูเหมือนจะเป็นโปรแกรมเมอร์จากภาษาอื่นที่ยังคงคิดในภาษาเหล่านั้น หากคุณต้องการเฉพาะออบเจ็กต์ของคลาสที่กำหนดในอาร์เรย์ให้ติดเฉพาะอ็อบเจ็กต์ของคลาสนั้นในนั้น หากคุณต้องการทดสอบว่าโค้ดของคุณทำงานอย่างถูกต้องให้ทดสอบ


137
ฉันคิดว่า 'โปรแกรมเมอร์ Cocoa ที่มีประสบการณ์' ไม่รู้ว่าพวกเขาขาดอะไรไป - ประสบการณ์กับ Java แสดงให้เห็นว่าตัวแปรประเภทช่วยเพิ่มความเข้าใจในโค้ดและทำให้การปรับแต่งเป็นไปได้มากขึ้น
tgdavies

12
การสนับสนุน Generics ของ Java นั้นเสียหายอย่างหนักเนื่องจากเป็นสิทธิ์ของตัวเองเพราะพวกเขาไม่ได้ใส่ไว้ตั้งแต่เริ่มต้น ...
dertoni

28
ต้องเห็นด้วยกับ @tgdavies ฉันคิดถึงความสามารถในการกระตุ้นและการปรับโครงสร้างใหม่ที่ฉันมีกับ C # เมื่อฉันต้องการการพิมพ์แบบไดนามิกฉันสามารถหาได้ใน C # 4.0 เมื่อฉันต้องการสิ่งที่ต้องการอย่างมากฉันก็สามารถมีได้ ฉันพบว่ามีเวลาและสถานที่สำหรับทั้งสองสิ่งนั้น
Steve

18
@charkrit มันเกี่ยวอะไรกับ Objective-C ที่ทำให้ 'ไม่จำเป็น'? คุณรู้สึกว่ามันจำเป็นไหมเมื่อคุณใช้ C #? ฉันได้ยินคนจำนวนมากบอกว่าคุณไม่จำเป็นต้องใช้ใน Objective-C แต่ฉันคิดว่าคนกลุ่มเดียวกันเหล่านี้คิดว่าคุณไม่ต้องการมันในภาษาใด ๆ ซึ่งทำให้เป็นเรื่องของความชอบ / สไตล์ไม่ใช่เรื่องจำเป็น
bacar

17
นี่ไม่เกี่ยวกับการอนุญาตให้คอมไพเลอร์ของคุณช่วยคุณค้นหาปัญหา แน่นอนว่าคุณสามารถพูดได้ว่า "ถ้าคุณต้องการเฉพาะออบเจ็กต์ของคลาสที่กำหนดในอาร์เรย์ให้ติดออบเจ็กต์ของคลาสนั้นไว้ในนั้นเท่านั้น" แต่ถ้าการทดสอบเป็นวิธีเดียวในการบังคับใช้คุณจะเสียเปรียบ ยิ่งคุณพบปัญหาอยู่ห่างจากการเขียนโค้ดมากเท่าใดปัญหานั้นก็ยิ่งมีค่าใช้จ่ายสูงขึ้นเท่านั้น
GreenKiwi

146

ยังไม่มีใครวางไว้ที่นี่ดังนั้นฉันจะทำ!

Tthis ได้รับการสนับสนุนอย่างเป็นทางการใน Objective-C แล้ว ใน Xcode 7 คุณสามารถใช้ไวยากรณ์ต่อไปนี้:

NSArray<MyClass *> *myArray = @[[MyClass new], [MyClass new]];

บันทึก

สิ่งสำคัญคือต้องทราบว่าสิ่งเหล่านี้เป็นคำเตือนของคอมไพเลอร์เท่านั้นและในทางเทคนิคคุณยังสามารถแทรกวัตถุใด ๆ ลงในอาร์เรย์ของคุณได้ มีสคริปต์ที่สามารถเปลี่ยนคำเตือนทั้งหมดให้เป็นข้อผิดพลาดซึ่งจะป้องกันการสร้าง


ฉันขี้เกียจอยู่ที่นี่ แต่ทำไมสิ่งนี้ถึงมีเฉพาะใน XCode 7 เราสามารถใช้nonnullใน XCode 6 ได้และเท่าที่ฉันจำได้มีการเปิดตัวในเวลาเดียวกัน นอกจากนี้การใช้แนวคิดดังกล่าวขึ้นอยู่กับเวอร์ชัน XCode หรือเวอร์ชัน iOS หรือไม่
Guven

@Guven - nullability มาใน 6 คุณถูกต้อง แต่ ObjC generics ไม่ได้ถูกนำมาใช้จนกว่า Xcode 7
Logan

ฉันค่อนข้างแน่ใจว่ามันขึ้นอยู่กับรุ่น Xcode เท่านั้น generics เป็นคำเตือนของคอมไพเลอร์เท่านั้นและไม่ได้ระบุไว้ที่รันไทม์ ฉันค่อนข้างแน่ใจว่าคุณสามารถรวบรวมระบบปฏิบัติการอะไรก็ได้ที่คุณต้องการ
Logan

2
@DeanKelly - คุณสามารถทำแบบนี้ได้: @property (nonatomic, strong) NSArray<id<SomeProtocol>>* protocolObjects; ดูน่าเบื่อเล็กน้อย แต่เคล็ดลับ!
Logan

1
@Logan ไม่ได้มีเพียงชุดของสคริปต์เท่านั้นที่ป้องกันการสร้างในกรณีที่ตรวจพบคำเตือน Xcode มีกลไกที่สมบูรณ์แบบชื่อ "Configuration" ลองดูที่boredzo.org/blog/archives/2009-11-07/warnings
adnako

53

นี่เป็นคำถามที่พบได้บ่อยสำหรับผู้ที่เปลี่ยนจากภาษาประเภทที่รุนแรง (เช่น C ++ หรือ Java) ไปเป็นภาษาที่พิมพ์ผิดหรือไดนามิกมากขึ้นเช่น Python, Ruby หรือ Objective-C ใน Objective-C อ็อบเจ็กต์ส่วนใหญ่สืบทอดมาจากNSObject(type id) (ส่วนที่เหลือสืบทอดมาจากคลาสรูทอื่น ๆ เช่นNSProxyและสามารถเป็นประเภทได้id) และข้อความใด ๆ สามารถส่งไปยังอ็อบเจ็กต์ใดก็ได้ แน่นอนว่าการส่งข้อความไปยังอินสแตนซ์ที่มันไม่รู้จักอาจทำให้เกิดข้อผิดพลาดรันไทม์ (และจะทำให้คอมไพเลอร์เตือนด้วยด้วยแฟล็ก -W ที่เหมาะสม) ตราบเท่าที่อินสแตนซ์ตอบสนองต่อข้อความที่คุณส่งคุณอาจไม่สนใจว่ามันเป็นของคลาสใด สิ่งนี้มักเรียกว่า "การพิมพ์เป็ด" เพราะ "ถ้ามันหลอกลวงเหมือนเป็ด [เช่นตอบสนองต่อตัวเลือก] มันก็คือเป็ด [เช่นมันสามารถจัดการกับข้อความได้ใครสนใจว่ามันเป็นคลาสไหน]"

คุณสามารถทดสอบว่าอินสแตนซ์ตอบสนองต่อตัวเลือกขณะรันด้วย-(BOOL)respondsToSelector:(SEL)selectorวิธีนี้หรือไม่ สมมติว่าคุณต้องการเรียกใช้เมธอดในทุกอินสแตนซ์ในอาร์เรย์ แต่ไม่แน่ใจว่าอินสแตนซ์ทั้งหมดสามารถจัดการกับข้อความได้ (ดังนั้นคุณจึงไม่สามารถใช้NSArray's -[NSArray makeObjectsPerformSelector:]ได้สิ่งนี้จะใช้ได้:

for(id o in myArray) {
  if([o respondsToSelector:@selector(myMethod)]) {
    [o myMethod];
  }
}

หากคุณควบคุมซอร์สโค้ดสำหรับอินสแตนซ์ที่ใช้เมธอดที่คุณต้องการเรียกใช้วิธีการทั่วไปมากขึ้นคือการกำหนด a @protocolที่มีเมธอดเหล่านั้นและประกาศว่าคลาสที่เป็นปัญหาใช้โปรโตคอลนั้นในการประกาศ ในการใช้งานนี้ a @protocolนั้นคล้ายคลึงกับ Java Interface หรือคลาสพื้นฐานที่เป็นนามธรรม C ++ จากนั้นคุณสามารถทดสอบความสอดคล้องกับโปรโตคอลทั้งหมดแทนที่จะตอบสนองต่อแต่ละวิธี ในตัวอย่างก่อนหน้านี้จะไม่สร้างความแตกต่างมากนัก แต่ถ้าคุณเรียกใช้หลายวิธีการอาจทำให้สิ่งต่างๆง่ายขึ้น จากนั้นตัวอย่างจะเป็น:

for(id o in myArray) {
  if([o conformsToProtocol:@protocol(MyProtocol)]) {
    [o myMethod];
  }
}

สมมติว่าdeclaresMyProtocol myMethodแนวทางที่สองนี้เป็นที่ชื่นชอบเพราะชี้แจงเจตนาของโค้ดมากกว่าแบบแรก

บ่อยครั้งหนึ่งในวิธีการเหล่านี้ทำให้คุณไม่ต้องสนใจว่าวัตถุทั้งหมดในอาร์เรย์เป็นประเภทที่กำหนดหรือไม่ หากคุณยังคงสนใจแนวทางภาษาไดนามิกมาตรฐานคือการทดสอบหน่วยการทดสอบหน่วยการทดสอบหน่วย เนื่องจากการถดถอยในข้อกำหนดนี้จะทำให้เกิดข้อผิดพลาดรันไทม์ (ไม่ใช่เวลาคอมไพล์) (อาจไม่สามารถกู้คืนได้) คุณจึงต้องมีการครอบคลุมการทดสอบเพื่อตรวจสอบพฤติกรรมเพื่อที่คุณจะได้ไม่ปล่อยผู้บุกรุกเข้าไปในป่า ในกรณีนี้ให้ทำการดำเนินการที่แก้ไขอาร์เรย์จากนั้นตรวจสอบว่าอินสแตนซ์ทั้งหมดในอาร์เรย์เป็นของคลาสที่กำหนด ด้วยการครอบคลุมการทดสอบที่เหมาะสมคุณไม่จำเป็นต้องมีค่าใช้จ่ายรันไทม์เพิ่มเติมในการยืนยันตัวตนอินสแตนซ์ คุณมีความครอบคลุมการทดสอบหน่วยที่ดีใช่ไหม


35
การทดสอบหน่วยไม่สามารถใช้แทนระบบประเภทที่เหมาะสมได้
tba

8
ใช่ใครต้องการเครื่องมือที่พิมพ์อาร์เรย์จะจ่ายได้ ฉันแน่ใจว่า @BarryWark (และใครก็ตามที่เคยสัมผัสโค้ดเบสใด ๆ ที่เขาต้องใช้อ่านทำความเข้าใจและสนับสนุน) มีรหัสครอบคลุม 100% อย่างไรก็ตามฉันพนันได้เลยว่าคุณไม่ได้ใช้ raw ids ยกเว้นในกรณีที่จำเป็น แต่มีมากกว่า Java coders ที่ส่งผ่านObjects ทำไมจะไม่ล่ะ? ไม่จำเป็นต้องใช้ถ้าคุณมีการทดสอบหน่วย? เนื่องจากมีอยู่และทำให้โค้ดของคุณสามารถบำรุงรักษาได้มากขึ้นเช่นเดียวกับอาร์เรย์ที่พิมพ์ ดูเหมือนผู้คนที่ลงทุนในแพลตฟอร์มโดยไม่ต้องการที่จะยอมรับประเด็นดังนั้นการคิดค้นเหตุผลว่าทำไมการละเลยนี้จึงเป็นประโยชน์
funkybro

"เป็ดพิมพ์" ?? ที่ฮา! ไม่เคยได้ยินมาก่อน
John Henckel

11

คุณสามารถคลาสย่อยNSMutableArrayเพื่อบังคับใช้ประเภทความปลอดภัย

NSMutableArrayเป็นคลัสเตอร์คลาสดังนั้นคลาสย่อยจึงไม่สำคัญ ฉันลงเอยด้วยการสืบทอดจากNSArrayและส่งต่อการเรียกร้องไปยังอาร์เรย์ภายในคลาสนั้น ผลที่ได้คือระดับที่เรียกว่าConcreteMutableArrayซึ่งเป็นเรื่องง่ายที่จะ subclass นี่คือสิ่งที่ฉันคิดขึ้น:

อัปเดต:ชำระเงินโพสต์บล็อกนี้จาก Mike Ashเกี่ยวกับคลาสย่อยคลัสเตอร์คลาส

รวมไฟล์เหล่านั้นไว้ในโปรเจ็กต์ของคุณจากนั้นสร้างประเภทที่คุณต้องการโดยใช้มาโคร:

MyArrayTypes.h

CUSTOM_ARRAY_INTERFACE(NSString)
CUSTOM_ARRAY_INTERFACE(User)

MyArrayTypes.m

CUSTOM_ARRAY_IMPLEMENTATION(NSString)
CUSTOM_ARRAY_IMPLEMENTATION(User)

การใช้งาน:

NSStringArray* strings = [NSStringArray array];
[strings add:@"Hello"];
NSString* str = [strings get:0];

[strings add:[User new]];  //compiler error
User* user = [strings get:0];  //compiler error

ความคิดอื่น ๆ

  • มันสืบทอดมาจากNSArrayเพื่อรองรับการทำให้เป็นอนุกรม / การแยกส่วน
  • ขึ้นอยู่กับรสนิยมของคุณคุณอาจต้องการลบล้าง / ซ่อนวิธีการทั่วไปเช่น

    - (void) addObject:(id)anObject


ดี แต่ตอนนี้ยังไม่มีการพิมพ์ที่ชัดเจนโดยการลบล้างวิธีการบางอย่าง ขณะนี้มีเพียงการพิมพ์ที่อ่อนแอ
Cœur

7

ดูที่https://github.com/tomersh/Objective-C-Genericsการใช้งาน generics แบบ compile-time (prerocessor-installed) สำหรับ Objective-C โพสต์บล็อกนี้มีภาพรวมที่ดี โดยทั่วไปคุณจะได้รับการตรวจสอบเวลาคอมไพล์ (คำเตือนหรือข้อผิดพลาด) แต่ไม่มีการลงโทษรันไทม์สำหรับข้อมูลทั่วไป


1
ฉันลองใช้แล้วเป็นความคิดที่ดีมาก แต่น่าเสียดายที่บั๊กกี้และไม่ได้ตรวจสอบองค์ประกอบที่เพิ่มเข้ามา
Binarian

4

โครงการ Github นี้ใช้ฟังก์ชันนั้นทุกประการ

จากนั้นคุณสามารถใช้<>วงเล็บเช่นเดียวกับที่คุณทำใน C #

จากตัวอย่างของพวกเขา:

NSArray<MyClass>* classArray = [NSArray array];
NSString *name = [classArray lastObject].name; // No cast needed

0

วิธีที่เป็นไปได้อาจเป็นคลาสย่อยของ NSArray แต่ Apple ไม่แนะนำให้ทำ มันง่ายกว่าที่จะคิดสองเท่าของความต้องการที่แท้จริงสำหรับ NSArray ที่พิมพ์ออกมา


1
ประหยัดเวลาในการตรวจสอบประเภทคงที่ในเวลารวบรวมการแก้ไขจะดียิ่งขึ้น มีประโยชน์อย่างยิ่งเมื่อคุณเขียน lib สำหรับการใช้งานระยะยาว
pinxue

0

ฉันสร้างคลาสย่อย NSArray ที่ใช้อ็อบเจ็กต์ NSArray เป็นตัวสำรอง ivar เพื่อหลีกเลี่ยงปัญหาเกี่ยวกับลักษณะคลัสเตอร์คลาสของ NSArray ต้องใช้บล็อกในการยอมรับหรือปฏิเสธการเพิ่มวัตถุ

เพื่ออนุญาตเฉพาะออบเจ็กต์ NSString คุณสามารถกำหนดAddBlockเป็น

^BOOL(id element) {
    return [element isKindOfClass:[NSString class]];
}

คุณสามารถกำหนด a FailBlockเพื่อตัดสินใจว่าจะทำอย่างไรหากองค์ประกอบล้มเหลวในการทดสอบ - ล้มเหลวอย่างงดงามสำหรับการกรองเพิ่มไปยังอาร์เรย์อื่นหรือ - นี่เป็นค่าเริ่มต้น - เพิ่มข้อยกเว้น

VSBlockTestedObjectArray.h

#import <Foundation/Foundation.h>
typedef BOOL(^AddBlock)(id element); 
typedef void(^FailBlock)(id element); 

@interface VSBlockTestedObjectArray : NSMutableArray

@property (nonatomic, copy, readonly) AddBlock testBlock;
@property (nonatomic, copy, readonly) FailBlock failBlock;

-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity;
-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock;
-(id)initWithTestBlock:(AddBlock)testBlock;    
@end

VSBlockTestedObjectArray.m

#import "VSBlockTestedObjectArray.h"

@interface VSBlockTestedObjectArray ()
@property (nonatomic, retain) NSMutableArray *realArray;
-(void)errorWhileInitializing:(SEL)selector;
@end

@implementation VSBlockTestedObjectArray
@synthesize testBlock = _testBlock;
@synthesize failBlock = _failBlock;
@synthesize realArray = _realArray;


-(id)initWithCapacity:(NSUInteger)capacity
{
    if (self = [super init]) {
        _realArray = [[NSMutableArray alloc] initWithCapacity:capacity];
    }

    return self;
}

-(id)initWithTestBlock:(AddBlock)testBlock 
             FailBlock:(FailBlock)failBlock 
              Capacity:(NSUInteger)capacity
{
    self = [self initWithCapacity:capacity];
    if (self) {
        _testBlock = [testBlock copy];
        _failBlock = [failBlock copy];
    }

    return self;
}

-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock
{
    return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0];
}

-(id)initWithTestBlock:(AddBlock)testBlock
{
    return [self initWithTestBlock:testBlock FailBlock:^(id element) {
        [NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element];
    } Capacity:0];
}


- (void)dealloc {
    [_failBlock release];
    [_testBlock release];
    self.realArray = nil;
    [super dealloc];
}


- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
    if(self.testBlock(anObject))
        [self.realArray insertObject:anObject atIndex:index];
    else
        self.failBlock(anObject);
}

- (void) removeObjectAtIndex:(NSUInteger)index
{
    [self.realArray removeObjectAtIndex:index];
}

-(NSUInteger)count
{
    return [self.realArray count];
}

- (id) objectAtIndex:(NSUInteger)index
{
    return [self.realArray objectAtIndex:index];
}



-(void)errorWhileInitializing:(SEL)selector
{
    [NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)];
}
- (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;}

@end

ใช้มันเช่น:

VSBlockTestedObjectArray *stringArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
    return [element isKindOfClass:[NSString class]];
} FailBlock:^(id element) {
    NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSString", element);
}];


VSBlockTestedObjectArray *numberArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
    return [element isKindOfClass:[NSNumber class]];
} FailBlock:^(id element) {
    NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSNumber", element);
}];


[stringArray addObject:@"test"];
[stringArray addObject:@"test1"];
[stringArray addObject:[NSNumber numberWithInt:9]];
[stringArray addObject:@"test2"];
[stringArray addObject:@"test3"];


[numberArray addObject:@"test"];
[numberArray addObject:@"test1"];
[numberArray addObject:[NSNumber numberWithInt:9]];
[numberArray addObject:@"test2"];
[numberArray addObject:@"test3"];


NSLog(@"%@", stringArray);
NSLog(@"%@", numberArray);

นี่เป็นเพียงตัวอย่างโค้ดและไม่เคยใช้ในแอปพลิเคชันจริง ในการทำเช่นนั้นอาจต้องใช้วิธีการของ mor NSArray


0

หากคุณผสม c ++ และ objective-c (เช่นใช้ไฟล์ประเภท mm) คุณสามารถบังคับใช้การพิมพ์โดยใช้คู่หรือทูเปิล ตัวอย่างเช่นในวิธีการต่อไปนี้คุณสามารถสร้างออบเจ็กต์ C ++ ประเภท std :: pair แปลงเป็นอ็อบเจ็กต์ประเภท OC wrapper (wrapper ของ std :: pair ที่คุณต้องการกำหนด) จากนั้นส่งต่อไปยังบางส่วน วิธีการ OC อื่น ๆ ซึ่งคุณต้องแปลงอ็อบเจ็กต์ OC กลับไปเป็นอ็อบเจ็กต์ C ++ เพื่อใช้งาน วิธี OC ยอมรับเฉพาะประเภทห่อหุ้ม OC เท่านั้นดังนั้นจึงมั่นใจได้ถึงความปลอดภัยของประเภท คุณยังสามารถใช้ tuple เทมเพลตแบบแปรผันโปรแกรมพิมพ์ดีดเพื่อใช้ประโยชน์จากคุณสมบัติ C ++ ขั้นสูงเพิ่มเติมเพื่ออำนวยความสะดวกในการพิมพ์

- (void) tableView:(UITableView*) tableView didSelectRowAtIndexPath:(NSIndexPath*) indexPath
{
 std::pair<UITableView*, NSIndexPath*> tableRow(tableView, indexPath);  
 ObjCTableRowWrapper* oCTableRow = [[[ObjCTableRowWrapper alloc] initWithTableRow:tableRow] autorelease];
 [self performSelector:@selector(selectRow:) withObject:oCTableRow];
}

0

สองเซ็นต์ของฉันจะ "สะอาดกว่า":

ใช้ typedefs:

typedef NSArray<NSString *> StringArray;

ในรหัสเราสามารถทำได้:

StringArray * titles = @[@"ID",@"Name", @"TYPE", @"DATE"];

0

ปี 2020 คำตอบที่ตรงไปตรงมา มันเกิดขึ้นจนฉันต้องการอาร์เรย์ที่ไม่แน่นอนที่มีประเภทของNSString.

ไวยากรณ์:

Type<ArrayElementType *> *objectName;

ตัวอย่าง:

@property(nonatomic, strong) NSMutableArray<NSString *> *buttonInputCellValues;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.