15

Tôi đang viết một API liên quan đến xử lý sự kiện và tôi muốn có thể sử dụng các khối cho trình xử lý. Các cuộc gọi lại thường sẽ muốn truy cập hoặc sửa đổi bản thân. Trong chế độ ARC, Clang cảnh báo rằng các khối tham chiếu đến bản thân có khả năng tạo ra một chu trình giữ lại, có vẻ như một cảnh báo hữu ích mà tôi muốn tiếp tục nói chung.Vô hiệu hoá cảnh báo vòng kín vòng lặp cho các khối tự tham chiếu

Tuy nhiên, đối với phần này của API của tôi, vòng đời của cuộc gọi lại và đối tượng chứa được duy trì bên ngoài. Tôi biết tôi có thể phá vỡ chu kỳ khi đối tượng nên được deallocated.

Tôi có thể tắt cảnh báo chu kỳ lưu giữ trên cơ sở mỗi tệp với #pragma clang diagnostic ignored "-Warc-retain-cycles", nhưng điều đó sẽ vô hiệu hóa cảnh báo cho toàn bộ tệp. Tôi có thể bao quanh các khối với một số #pragma clang diagnostic pushpop xung quanh cảnh báo đó, nhưng điều đó làm cho các khối xấu xí.

Tôi cũng có thể nhận cảnh báo để biến mất bằng cách tham chiếu biến __weak trỏ đến tự thay vì tự tham chiếu trực tiếp, nhưng điều đó làm cho các khối khó sử dụng hơn.

Giải pháp tốt nhất mà tôi đã đưa ra là macro này mà không được vô hiệu chẩn đoán xung quanh khối:

#define OBSERVE(OBJ, OBSERVEE, PATH, CODE) \ 
[(OBJ) observeObject:(OBSERVEE) forKeyPath:(PATH) withBlock:^(id obj, NSDictionary *change) { \ 
_Pragma("clang diagnostic push") \ 
_Pragma("clang diagnostic ignored \"-Warc-retain-cycles\"") \ 
do { CODE; } while(0); \ 
_Pragma("clang diagnostic pop") \ 
}]; 

đó làm việc, nhưng nó không phải là rất có thể phát hiện cho người dùng API, nó không cho phép lồng nhau các nhà quan sát, và nó tương tác kém với trình soạn thảo của XCode. Có cách nào tốt hơn để vô hiệu hóa hoặc tránh cảnh báo?

+10

Tạo tham chiếu '__weak' thành' self' theo nghĩa đen có một dòng mã. Tôi nghĩ rằng sửa chữa vấn đề trong trường hợp này là tốt hơn so với cố gắng để làm giảm bớt các triệu chứng. Làm thế nào để tham chiếu đến 'weakSelf' thay vì' self' làm cho khối dễ chịu hơn để sử dụng? –

+3

Nó ít dễ chịu hơn theo một vài cách. Những người nghe thường khá ngắn, đôi khi là một phát biểu duy nhất. Khai báo __weak tăng gấp đôi kích thước của người nghe. Nó cũng có nghĩa là bạn cần phải đủ điều kiện truy cập tài sản hơn là sử dụng một suy luận tự. Tôi sẽ đồng ý rằng giải pháp hiện tại của tôi có lẽ tệ hơn là chỉ sử dụng __weak, nhưng tôi đã hy vọng có được một giải pháp tốt hơn thông qua câu hỏi này. –

+1

Bạn có thể thay đổi nguyên mẫu của khối hoàn thành của mình để chấp nhận đối số "tự" không? Bây giờ mã mà bạn vượt qua các khối của bạn sẽ trông giống nhau (ngoại trừ chấp nhận một đối số thêm) và bạn có thể loại bỏ các cảnh báo. (ví dụ: API của bạn cũng truyền đối tượng được đề cập đến khối của bạn) – nielsbot

Trả lời

7

Để bắt đầu, có một cách đơn giản để vô hiệu hóa các cảnh báo cho một số dòng mã sử dụng #pragma:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "<#A warning to ignore#>" 
<#Code that issues a warning#> 
#pragma clang diagnostic pop 

Nhưng tôi sẽ không sử dụng nó trong trường hợp đặc biệt này bởi vì nó sẽ không giải quyết được vấn đề này , nó sẽ chỉ ẩn nó khỏi nhà phát triển. Tôi thà đi với giải pháp mà Mark đề xuất. Để tạo một tham chiếu yếu, bạn có thể làm một trong những bên ngoài sau của khối:

__weak typeof(self) weakSelf = self; // iOS ≥ 5 
__unsafe_unretained typeof(self) unsafeUnretainedSelf = self; // 5 > iOS ≥ 4 
__block typeof(self) blockSelf = self; // ARC disabled 
0

các LLVM mới là tốt hơn khả năng phát hiện/ngăn ngừa như giữ lại chu kỳ chờ LLVM vận chuyển với iOS6 hoặc làm cách alex với tạo một var yếu.

tắt cảnh báo là một ý tưởng tồi!

1

Tôi cho rằng vô hiệu hóa cảnh báo hiện là cách chính xác duy nhất để thực hiện, vì trình biên dịch nói: Không quan tâm đến chu kỳ lưu giữ này, tôi biết và tôi sẽ tự mình xử lý người quan sát. Giới thiệu một tham chiếu yếu là một giải pháp tốn kém vì nó đi kèm với CPU thời gian chạy và phí trên bộ nhớ.

0

tôi đã viết macro sau, mà Tôi nghĩ, là khá thông minh ...

#define CLANG_IGNORE_HELPER0(x) #x 
#define CLANG_IGNORE_HELPER1(x) CLANG_IGNORE_HELPER0(clang diagnostic ignored x) 
#define CLANG_IGNORE_HELPER2(y) CLANG_IGNORE_HELPER1(#y) 

#define CLANG_POP _Pragma("clang diagnostic pop") 
#define CLANG_IGNORE(x)\ 
    _Pragma("clang diagnostic push");\ 
    _Pragma(CLANG_IGNORE_HELPER2(x)) 

Nó cho phép bạn làm tất cả các loại điều thú vị (không Xcode haranguing bạn), chẳng hạn như ..

CLANG_IGNORE(-Warc-retain-cycles) 
[object performBlock:^(id obj){ [obj referToSelfWithoutWarning:self]; }]; 
CLANG_POP 

Bạn có thể đặt trong bất kỳ cờ cảnh báo nào và Clang sẽ chú ý đến ý tưởng của bạn ...

CLANG_IGNORE(-Warc-performSelector-leaks); 
return [self performSelector:someIllBegotSelector withObject:arcFauxPas]; 
CLANG_POP 

Sau đó, một lần nữa, những lời cảnh báo thường là có một lý do. Đảng poppers.

0

Để giải quyết vấn đề về sự lộn xộn của việc tạo tham chiếu yếu, tôi đặt nó vào macro. Nó sử dụng bộ tiền xử lý để tạo một biến mới có cùng tên nhưng với tiền tố ('w', trong trường hợp này, tôi tránh 'yếu' vì điều đó sẽ quá mức và lộn xộn hơn với các quy tắc viết hoa):

#define WEAK_VAR(NAME) __unsafe_unretained typeof(NAME) w##NAME = NAME 

... 
WEAK_VAR(self); 
self.block = ^{ 
    [wself doStuff]; 
}; 

Nếu, otoh, một tham chiếu yếu là không mong muốn, không sử dụng nó! Tôi thích giải pháp nielsbot truyền đối tượng như một tham số (khi có thể, tất nhiên).

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