2011-12-09 37 views
5

Tôi có câu hỏi này here (cũng như các câu hỏi khác về SO) và tài liệu của Apple về bộ sưu tập Objective-C và liệt kê nhanh. Điều không rõ ràng là nếu một số NSArray được điền với các loại khác nhau và vòng lặp được tạo như:liệt kê nhanh về NSArray của các loại khác nhau

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

Chính xác điều gì xảy ra ở đây? Vòng lặp có bỏ qua bất kỳ thứ gì không phải là NSString không? Ví dụ, nếu (vì lợi ích của đối số), UIView nằm trong mảng, điều gì sẽ xảy ra khi vòng lặp gặp mục đó?

+3

nhanh liệt kê "mất chữ của bạn" trên lớp. @awfullyjohn cung cấp giải pháp tốt nhất để xử lý một mảng với các thành viên của các lớp không xác định. Không có bộ lọc ngầm nào xảy ra và có thể dẫn đến việc gọi phương thức mà người nhận không thể xử lý ... sự cố –

Trả lời

9

Tại sao bạn muốn thực hiện điều đó? Tôi nghĩ rằng sẽ gây ra hành vi buggy và không mong muốn. Nếu mảng của bạn được phổ biến với các yếu tố khác nhau, sử dụng này để thay thế:

for (id object in myArray) { 
    // Check what kind of class it is 
    if ([object isKindOfClass:[UIView class]]) { 
     // Do something 
    } 
    else { 
     // Handle accordingly 
    } 
} 

gì bạn đang làm trong ví dụ của bạn là một cách hiệu quả giống như,

for (id object in myArray) { 
    NSString *string = (NSString *)object; 
    NSLog(@"%@\n", string); 
} 

Chỉ vì bạn cast object như (NSString *) không nghĩa là string sẽ thực sự trỏ đến đối tượng NSString. Gọi NSLog() theo cách này sẽ gọi phương thức - (NSString *)description theo số NSObject protocol, lớp được tham chiếu bên trong mảng có thể hoặc không phù hợp. Nếu nó phù hợp, nó sẽ in nó. Nếu không, nó sẽ sụp đổ.

+1

Một điểm tốt, nhưng điều này không trả lời được câu hỏi. – PengOne

+0

Câu hỏi đặt ra là một sự hiểu biết sâu sắc hơn về Mục tiêu-C hơn là thực sự làm một cái gì đó như thế này. Ngoài ra, tôi đã làm việc C# gần đây, nơi các loại đi vào một bộ sưu tập có thể được xác định. –

+1

Đúng. Tôi sẽ cập nhật câu trả lời của tôi, nhưng về cơ bản, bạn đánh tôi với nó. – john

2

Câu hỏi thú vị. Cú pháp chung nhất cho liệt kê nhanh là

for (NSObject *obj in myArray) 
    NSLog(@"%@\n", obj); 

Tôi tin rằng bằng cách làm

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

thay vào đó, bạn chỉ đơn giản là đúc từng đối tượng như một NSString. Đó là, tôi tin rằng ở trên là tương đương với

for (NSObject *obj in myArray) { 
    NSString *string = obj; 
    NSLog(@"%@\n", string); 
} 

tôi không thể tìm thấy đề cập đến chính xác về điều này trong Apple documentation for Fast Enumeration, nhưng bạn có thể kiểm tra xem nó trên một ví dụ và xem những gì sẽ xảy ra.

+1

Phiên bản "chung chung nhất" không phải là 'cho (id obj in arr)' (vì nó bao gồm (số nhỏ của) các đối tượng không xuất phát từ 'NSObject')? –

2

Tôi vừa thử một ví dụ nhanh ... Đây là mã của tôi.

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1]; 
NSNumber *number = [NSNumber numberWithInteger:6]; 
[array addObject:number]; 
[array addObject:@"Second"]; 

Bây giờ nếu tôi chỉ cần đăng nhập đối tượng, không sao cả. Ví dụ NSNumber đang được truyền dưới dạng NSString, nhưng cả hai phương thức đều phản hồi lại -description, do đó, đây không phải là vấn đề.

for (NSString *string in array) 
{ 
    NSLog(@"%@", string); 
} 

Tuy nhiên, nếu tôi cố gắng để đăng nhập -length trên NSString ...

for (NSString *string in array) 
{ 
    NSLog(@"%i", string.length); 
} 

... nó ném một NSInvalidArgumentExceptionNSNumber không đáp ứng với bộ chọn -length. Truyện ngắn, Objective-C cho bạn rất nhiều sợi dây thừng. Đừng treo cổ với nó.

+0

NSNumber không được truyền dưới dạng NSString. Cả NSNumber & NSString đều là hậu duệ của NSObject, trong đó NSLog gọi 'description', giống như bạn nói. Nhưng không có đúc liên quan. –

+0

Ồ tôi hiểu rồi. Tôi đoán tôi chỉ nhầm lẫn với tính năng hoàn tất mã. Như tôi đã viết ví dụ, tôi đã không nhận được cảnh báo về việc nhắn tin '-length' trên một thể hiện của' NSNumber'. –

+0

Ah! Được rồi ... Giờ tôi cũng hiểu ý anh là gì. Các NSNumber đang được đúc như một NSString thành 'chuỗi'. Tôi nghĩ rằng bạn đã nói rằng NSLog đã làm việc đúc (từ đề cập đến 'mô tả'). Lỗi của tôi! –

3

Bạn phải hiểu rằng con trỏ trong obj-c không có thông tin loại. Ngay cả khi bạn viết NSString*, nó chỉ là một kiểm tra biên dịch. Trong thời gian chạy, mọi thứ chỉ là id.

Thời gian chạy Obj-c không bao giờ kiểm tra xem các đối tượng có thuộc lớp đã cho hay không. Bạn có thể đặt NSNumbers vào con trỏ NSString mà không gặp vấn đề gì. Một lỗi xuất hiện chỉ khi bạn cố gắng gọi một phương thức (gửi một tin nhắn) mà không được xác định trên đối tượng.

Tính năng liệt kê nhanh hoạt động như thế nào? Nó giống hệt như:


for (NSUInteger i = 0; i < myArray.count; i++) { 
    NSString* string = [myArray objectAtIndex:i]; 

    [...] 
} 

Chỉ nhanh hơn vì nó hoạt động ở mức thấp hơn.

1

Kể từ khi đáp ứng tất cả của NSObject để isKindOfClass, bạn vẫn có thể giữ được đúc ở mức tối thiểu:

for(NSString *string in myArray) { 
    if (![string isKindOfClass:[NSString class]]) 
     continue; 
    // proceed, knowing you have a valid NSString * 
    // ... 
} 
Các vấn đề liên quan