是否可以将警告静音在" performSelector"并收到返回值或对象?

时间:2016-10-04 16:35:44

标签: ios objective-c automatic-ref-counting

我熟悉这个ARC警告的解决方案(performSelector may cause a leak because its selector is unknown),并且在大多数情况下已经实现了它们,但我似乎无法找到一种方法来正确获取选择器的返回值只是压制警告。

似乎可能无法或不应该完成,但重写代码逻辑(由他人开发)太耗费时间。

代码示例:

NSString *message = [callback performSelector:validatorSel withObject:textCell.textField.text];

2 个答案:

答案 0 :(得分:1)

如果知道validatorSel不以allocnew开头,或者名字中有copy(或Copy),那么知道没有涉及内存管理覆盖(很少见),那么默认内存管理在这里是正确的,你可以用适当的#pragma来抑制警告。如果你无法证明这些事情,那么这可能会崩溃,这就是为什么会有警告。

如果您无法证明上述要求,那么在ARC下无法使其安全。你要么必须在没有ARC的情况下构建它,要么重写它。

答案 1 :(得分:0)

从您的代码示例中,您似乎期望一个方法的选择器,该方法需要NSText *并返回NSString *。因此,从您的链接答案中,您可以确定此方法的实现具有函数类型:

NSString *(*)(ID, SEL, NSText *)

此处ID可以替换为callback的类型,NSText *可以替换为textCell.textField.text的实际类型,如果我们的猜测是绞尽脑的。

再次从您的链接答案中,您可以获取实现并使用以下方法调用它:

NSString *(*implementation)(ID, SEL, NSText *)
   = (void *)[callback methodForSelector: performSelector:validatorSel];
NSString *message = implementation(callback, validatorSel, textCell.textField.text);

正如@RobNapier正确地指出,如果选择器没有返回保留值,这在ARC下是安全的,例如对于正常的[*]选择器,如果它是 init 的成员,复制方法系列。现在,您不太可能为validatorSel传递 init 系列方法,因为这需要callback作为对alloc的引用但不是init&#39} ed对象,所以我们现在可以忽略那个[#]。要测试其他两个系列,您可以使用以下代码:

NSString *message; // for the return value of the selector
NSString *selName = NSStringFromSelector(validatorSel); // get string name of selector
if ([selName hasPrefix:@"new"]     // starts with new,
    || [selName hasPrefix:@"copy"] // or copy,
    || [selName rangeOfString:@"Copy"].location != NSNotFound) // or contains "Copy"
{
   // need to handle returning a retained object
   ...
}
else
{
   // normal case
   NSString *(*implementation)(ID, SEL, NSText *)
      = (void *)[callback methodForSelector: performSelector:validatorSel];
   message = implementation(callback, validatorSel, textCell.textField.text);
}

这就是如何在ARC下为 copy new 系列方法正确处理返回值......

处理复制家庭方法

ARC知道方法或函数通过放置在方法/函数类型上的属性返回保留对象。 命名约定只是语言推断属性的方式(如果不存在),可以使用方法/函数声明中的NS_RETURNS_RETAINED宏手动指定。所以上面缺少的代码就是:

{
   // need to handle returning a retained object
   NSString *(*implementation)(ID, SEL, NSText *) NS_RETURNS_RETAINED
      = (void *)[callback methodForSelector: performSelector:validatorSel];
   message = implementation(callback, validatorSel, textCell.textField.text);
}

implementation的修改类型告诉ARC它将返回一个保留对象,ARC将像处理已知 copy new 家庭方法。

HTH

注意:处理 init 系列方法

我们跳过 init 系列不仅因为它不太可能,而且因为它的行为不同 - init 系列方法使用对象引用他们被召唤,也就是说他们希望传递一个他们拥有的拥有对象,并在需要时将其释放。毫不奇怪,消耗参数也由属性指示,就像返回保留对象一样。好奇的读者可能希望确定所需的代码,即使需要它的可能性很小。

[*] A"正常" selector是一个符合Objective-C标准命名约定的方法,并且不使用属性以违反标准约定的方式更改内存所有权行为。只支持标准约定不是一个很大的限制,公约的重点在于代码依赖于它们!

[#]你当然不太可能传递 new 系列选择器,callback通常必须是对类对象的引用,但处理它是与 copy 系列相同,因此我们已将其包括在内。