The code
[self.foo someMethod:bar withCompletion:^{ NSLog(@"%@", self.foo); }];
usually does not create a save loop. If someMethod:withCompletion: just calls the block and returns, there is no hold loop at all. ( -[NSArray enumerateObjectsUsingBlock:] - example.)
Only if someMethod:withCompletion: "remembers" a block that will be executed later, is there a possible save loop. Thus, clang uses heuristics to decide whether this method is βsetterβ, which stores the block in the Foo property, which will be executed later.
-set<Key> and -add<Key> are key-value-encoded access patterns to set a property or add a value to relationships (for many), and this is exactly what clang checks for.
This can be seen in the 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()); }
which is called here:
/// Check a message send to see if it 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 */ }
Your setupBar method setupBar not considered a method similar to the setter-like method because "set" is not followed by an uppercase letter.
Martin r
source share