コード
[self.foo someMethod:bar withCompletion:^{
NSLog(@"%@", self.foo);
}];
通常、保持サイクルは作成されません。ブロックを呼び出して戻るだけならsomeMethod:withCompletion:
、保持サイクルはまったくありません。(-[NSArray enumerateObjectsUsingBlock:]
は一例です。)
someMethod:withCompletion:
後で実行されるブロックを「記憶」している場合にのみ、保持サイクルが可能です。そのため、clang はヒューリスティックを使用して、ブロックを のプロパティに格納してFoo
後で実行する「setter のような」メソッドであるかどうかを判断します。
-set<Key>
および-add<Key>
は、プロパティを設定したり、(対多) 関係に値を追加したりするための Key-Value コーディングのアクセサ パターンであり、これはまさに clang がチェックするものです。
これは、 Clang ソース コードで確認できます。
/// 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());
}
ここで呼び出されます:
/// 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
*/
}
「set」の後に大文字が続かないため、このメソッドは「セッターのような」メソッドとして扱われsetupBar
ません。