Tôi có đặt thuộc tính thành nil trong dealloc khi sử dụng ARC không?


125

Tôi đang cố gắng học đếm số tham chiếu tự động trong iOS 5. Bây giờ phần đầu tiên của câu hỏi này sẽ dễ dàng:

  1. Có đúng không khi tôi KHÔNG cần phải viết các tuyên bố thuộc tính phát hành rõ ràng trong dealloc của mình khi sử dụng ARC? Nói cách khác, có đúng là sau đây KHÔNG cần một thỏa thuận rõ ràng?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Câu hỏi tiếp theo và quan trọng hơn của tôi đến từ một dòng trong tài liệu Ghi chú chuyển đổi sang ARC :

    Bạn không phải (thực sự không thể) phát hành các biến thể hiện, nhưng bạn có thể cần phải gọi [self setDelegate: nil] trên các lớp hệ thống và mã khác không được biên dịch bằng ARC.

    Điều này đặt ra câu hỏi: làm thế nào để tôi biết các lớp hệ thống nào không được biên dịch với ARC? Khi nào tôi nên tạo dealloc của riêng mình và thiết lập rõ ràng các thuộc tính giữ lại thành không? Tôi có nên giả sử tất cả các lớp khung NS và UI được sử dụng trong các thuộc tính yêu cầu deallocs rõ ràng không?

Có rất nhiều thông tin về SO và các nơi khác về các phương thức giải phóng ngà sao lưu tài sản khi sử dụng theo dõi tham chiếu thủ công, nhưng tương đối ít về điều này khi sử dụng ARC.

Câu trả lời:


197

Câu trả lời ngắn : không, bạn không cần phải loại bỏ các thuộc tính trong deallocARC.

Câu trả lời dài : Bạn không bao giờ nên bỏ qua các thuộc tính dealloc, ngay cả trong quản lý bộ nhớ thủ công.

Trong MRR, bạn nên giải phóng ngà của mình . Xóa các thuộc tính có nghĩa là gọi setters, có thể gọi mã mà nó không nên chạm vào dealloc(ví dụ: nếu lớp của bạn hoặc một lớp con, ghi đè lên setter). Tương tự, nó có thể kích hoạt thông báo KVO. Phát hành ngà thay vì tránh những hành vi không mong muốn này.

Trong ARC, hệ thống sẽ tự động giải phóng bất kỳ chiếc ngà nào cho bạn, vì vậy nếu đó là tất cả những gì bạn đang làm, bạn thậm chí không phải thực hiện dealloc. Tuy nhiên, nếu bạn có bất kỳ ngà phi đối tượng nào cần xử lý đặc biệt (ví dụ: bộ đệm được phân bổ mà bạn cần free()), bạn vẫn phải xử lý những cái trong đó dealloc.

Hơn nữa, nếu bạn đã đặt mình là đại biểu của bất kỳ đối tượng nào, bạn nên hủy đặt mối quan hệ đó dealloc(đây là một chút về cách gọi [obj setDelegate:nil]). Lưu ý về việc thực hiện điều này trên các lớp không được biên dịch với ARC là một cái gật đầu đối với các thuộc tính yếu. Nếu lớp đánh dấu rõ ràng thuộc tính của nó delegateweakthì bạn không phải làm điều này, bởi vì bản chất của các thuộc tính yếu có nghĩa là nó sẽ bị loại ra cho bạn. Tuy nhiên, nếu thuộc tính được đánh dấu assignthì bạn nên bỏ nó ra dealloc, nếu không, lớp bị bỏ lại với một con trỏ lơ lửng và có khả năng sẽ sụp đổ nếu nó cố gắng nhắn tin cho đại biểu của nó. Lưu ý rằng điều này chỉ áp dụng cho các mối quan hệ không giữ lại, chẳng hạn như các đại biểu.


2
Điều này thật ý nghĩa! Hãy để tôi hỏi bạn điều này mặc dù: một kịch bản phổ biến tôi có là tôi có một MyController : UIViewControllerlớp tạo và sở hữu một UIView và cũng đặt đại biểu của khung nhìn cho chính nó. Nó là chủ sở hữu duy nhất của quan điểm đó. Khi bộ điều khiển được dealloc'ed, thì khung nhìn cũng sẽ được dealloc'ed. Liệu nó có quan trọng nếu con trỏ đại biểu đang treo lủng lẳng?
emfurry

4
@emfurry: Có lẽ là không, bởi vì vào thời điểm bộ điều khiển khung nhìn của bạn chết, chính khung nhìn không nên nằm trong hệ thống phân cấp chế độ xem và không nên làm bất cứ điều gì, nhưng tốt nhất không nên đưa ra các giả định. Điều gì sẽ xảy ra nếu chế độ xem được lên lịch không đồng bộ sẽ được thực hiện sau đó và chế độ xem kết thúc vượt quá trình điều khiển chế độ xem của nó trong một thời gian ngắn (ví dụ do công việc không đồng bộ giữ chế độ xem tạm thời)? Tốt nhất là chỉ cần làm cho đại biểu được an toàn. Và trên thực tế, nếu quan điểm trong câu hỏi là a UIWebView, các tài liệu nói rõ bạn cần phải loại bỏ đại biểu.
Lily Ballard

3
@zeiteisen: Số unsafe_unretainedchính xác tương đương với một assigntài sản và là hành vi bình thường đối với các mối quan hệ được ủy quyền theo MRR, và những điều này cần phải được loại bỏ.
Lily Ballard

4
Tôi không đồng ý với tuyên bố về việc không sử dụng setters trong dealloc với MRC. Apple không khuyến nghị nhưng họ cũng làm điều đó trong mã của họ. Bạn thực sự có thể tạo ra các vấn đề mới bằng cách không sử dụng setter. Có một số cuộc thảo luận lớn về nó. Điều quan trọng là viết chính xác setter (nó phải hành xử chính xác nếu bạn truyền cho nó một giá trị không) và đôi khi xem thứ tự sắp xếp.
Sulthan

7
@Sulthan: Có hay không sử dụng setters trong dealloc là một con giun khổng lồ, nhưng về cơ bản, vị trí của tôi sôi lên: bạn muốn gọi càng ít mã càng tốt trong dealloc. Setters có xu hướng bao gồm các tác dụng phụ, hoặc bằng cách ghi đè trong các lớp con hoặc thông qua KVO hoặc các cơ chế khác. Tác dụng phụ trong dealloc đặc biệt nên tránh như bệnh dịch hạch. Nếu bạn có thể có thể loại bỏ một cuộc gọi phương thức từ dealloc, bạn nên làm như vậy. Điều này được đơn giản hóa thành: không gọi setters trong dealloc.
Lily Ballard

2

Chỉ cần đưa ra câu trả lời ngược lại ...

Câu trả lời ngắn : không, bạn không cần phải loại bỏ các thuộc tính tự động tổng hợp trong deallocARC. Và bạn không phải sử dụng setter cho những người trong init.

Câu trả lời dài : Bạn nên loại bỏ các thuộc tính tổng hợp tùy chỉnh trong dealloc, ngay cả dưới ARC. Và bạn nên sử dụng setter cho những người trong init.

Vấn đề là các thuộc tính tổng hợp tùy chỉnh của bạn phải an toàn và đối xứng về việc vô hiệu hóa.

Một setter có thể cho một bộ đếm thời gian:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

Một trình thiết lập có thể cho một cuộn, xem bảng, xem web, trường văn bản, ...:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

Một trình thiết lập có thể cho một thuộc tính KVO:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

Sau đó, bạn không cần phải sao chép bất kỳ mã cho dealloc, didReceiveMemoryWarning, viewDidUnload, ... và tài sản của bạn một cách an toàn có thể được công khai. Nếu bạn lo lắng về việc không có tài sản dealloc, thì có lẽ đã đến lúc bạn kiểm tra lại setters của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.