2011-01-12 22 views
7

Tôi có một đoạn mã trong ứng dụng iPhone, loại bỏ tất cả các bản xem trước khỏi lớp con UIView. Có vẻ như sau:Sự khác biệt về hành vi giữa UIView.subviews và [NSView subviews]

NSArray* subViews = self.subviews; 
for(UIView *aView in subViews) { 
    [aView removeFromSuperview]; 
} 

Điều này làm việc tốt. Trong thực tế, tôi chưa bao giờ thực sự suy nghĩ nhiều cho đến khi tôi thử gần giống với một ứng dụng Mac OS X (từ một phân lớp NSView):

NSArray* subViews = [self subviews]; 
for(NSView *aView in subViews) { 
    [aView removeFromSuperview]; 
} 

Điều đó hoàn toàn không hiệu quả. Cụ thể, tại thời gian chạy, tôi có được điều này:

*** Collection <NSCFArray: 0x1005208a0> was mutated while being enumerated. 

tôi đã kết thúc làm việc đó như vậy:

NSArray* subViews = [[self subviews] copy]; 
for(NSView *aView in subViews) { 
    [aView removeFromSuperview]; 
} 
[subViews release]; 

Đó là tốt. Điều gì khiến tôi lo lắng, đó là lý do tại sao nó hoạt động trên iPhone?

subviews là một tài sản bản sao:

@property(nonatomic,readonly,copy) NSArray *subviews; 

Suy nghĩ đầu tiên của tôi đã, thu khí có lẽ @ synthesize'd trả về một bản sao khi thuộc tính bản sao được xác định. The doc là rõ ràng về ngữ nghĩa của bản sao cho người định cư, nhưng dường như không nói theo cách nào cho getters (hoặc ít nhất, điều đó không rõ ràng đối với tôi). Và thực tế, làm một vài thử nghiệm của riêng tôi, điều này rõ ràng dường như không phải là trường hợp. Điều đó tốt, tôi nghĩ việc trả lại một bản sao sẽ có vấn đề, vì một vài lý do.

Vì vậy, câu hỏi đặt ra là: mã trên hoạt động như thế nào trên iPhone? NSView rõ ràng đang trả về một con trỏ tới mảng phụ của thực tế, và có lẽ UIView thì không. Có lẽ nó chỉ đơn giản là một chi tiết triển khai của UIView và tôi không nên làm việc về nó.

Có ai có thể cung cấp thông tin chi tiết nào không?

Trả lời

13

Đây là lỗi trong -[NSView subviews]. Tôi có thể thề rằng nó đã được sửa cho Snow Leopard, nhưng bây giờ không thể tìm được bằng chứng nào.

May mắn thay, có một cách đơn giản để loại bỏ tất cả các subviews:

[self setSubviews:[NSArray array]]; 
+3

Đó là chỉ một @ Mike lỗi. Nó chỉ là [someNSView subviews] trả về con trỏ tới mảng subviews, trong khi [someUIView subviews] trả về bản sao của mảng đó. Đây là lý do tại sao nó hoạt động tốt trên iOS. – jackal

2

Vâng, đó chỉ là cách Apple triển khai nó. Trên mac, các bản xem trước trả về mảng (có thể thay đổi) thực tế được sử dụng bởi khung nhìn, vì vậy bạn không thể sử dụng liệt kê nhanh trong khi thêm hoặc xóa các khung nhìn. Nếu bạn muốn sử dụng reverseObjectEnumerator, bạn có thể. Không sử dụng điều tra thông thường bởi vì nó có thể bỏ qua các cuộc phỏng vấn khi chúng được di chuyển lên để thay thế những người bị loại bỏ. Tuy nhiên, trong iOS, Apple dường như đã nhận ra vấn đề này và sửa nó bằng cách trả lại một bản sao tự động. Khai báo tài sản chỉ mô tả cách nó được thiết lập, nhưng táo đã chọn để sao chép cho getter quá.

3

Better sử dụng

while([self.subviews count] > 0){ 
    [[self.subviews objectAtindex:0] removeFromSuperview]; 
} 

Hope trợ giúp này.

Các vấn đề liên quan