2013-03-20 27 views
7

Tôi ngạc nhiên khi thấy những hành vi sau đây ...Các khối giữ lại chu kỳ từ quy ước đặt tên?

@interface Foo : NSObject 

- (void)addBar:(id)aBar withCompletion:(void(^)(void))completion; 

@end 

@interface AwesomeClass : NSObject 

@property (strong, nonatomic) Foo *foo; 

- (void)doSomethingWithBar:(id)bar; 

@end 

@implementation AwesomeClass 

- (void)doSomethingWithBar:(id)bar 
{ 
    [self.foo addBar:bar withCompletion:^{ 
     NSLog(@"%@", self.foo); 
    }]; 
} 

Trong Xcode 4.6.1 tôi nhận được một cảnh báo trong việc thực hiện -doSomethingWithBar: rằng "chụp 'tự' mạnh mẽ trong khối này là khả năng dẫn đến một giữ chu trình. "

Tuy nhiên, nếu tôi đổi tên tên của phương thức -addBar:withCompletion: thành -setupBar:withCompletion: cảnh báo này sẽ biến mất. Dường như sự ngạc nhiên của tôi bằng cách này minh họa tôi đã có một khoảng trống trong kiến ​​thức của tôi về các quy ước đặt tên Objective-C!

+1

Thử biên dịch lại. Cảnh báo không phải là "đi xa", nhiều như Xcode là ngu ngốc và đỏ bừng các cảnh báo LLVM tạo ra thời gian qua xung quanh – CodaFi

Trả lời

19

[self.foo someMethod:bar withCompletion:^{ 
    NSLog(@"%@", self.foo); 
}]; 

thường không tạo ra một chu kỳ giữ lại. Nếu someMethod:withCompletion: chỉ cần gọi khối và trả về, không có chu kỳ giữ lại nào cả. (-[NSArray enumerateObjectsUsingBlock:] là một ví dụ.)

Chỉ khi someMethod:withCompletion: "nhớ" khối sẽ được thực thi sau này, có thể có chu kỳ giữ lại. Vì vậy, clang sử dụng một heuristic để quyết định nếu nó là một phương pháp "giống như setter" lưu trữ khối vào một tài sản của Foo để được thực thi sau này.

-set<Key>-add<Key> là mẫu truy cập trong Mã hóa khóa-giá trị để đặt thuộc tính hoặc thêm giá trị cho mối quan hệ (nhiều) và đó chính xác là những gì kiểm tra.

Điều này có thể được nhìn thấy trong Clang source code:

/// Check for a keyword selector that starts with the word 'add' or 
/// 'set'. 
static bool isSetterLikeSelector(Selector sel) { 
    if (sel.isUnarySelector()) return false; 

    StringRef str = sel.getNameForSlot(0); 
    while (!str.empty() && str.front() == '_') str = str.substr(1); 
    if (str.startswith("set")) 
    str = str.substr(3); 
    else if (str.startswith("add")) { 
    // Specially whitelist 'addOperationWithBlock:'. 
    if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock")) 
     return false; 
    str = str.substr(3); 
    } 
    else 
    return false; 

    if (str.empty()) return true; 
    return !islower(str.front()); 
} 

được gọi ở đây:

/// Check a message send to see if it's likely to cause a retain cycle. 
void Sema::checkRetainCycles(ObjCMessageExpr *msg) { 
    // Only check instance methods whose selector looks like a setter. 
    if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector())) 
    return; 

    /* 
    * rest omitted 
    */ 

} 

phương pháp setupBar của bạn là không coi là phương pháp "setter-like" bởi vì "thiết lập" không được theo sau bởi một chữ hoa.

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