是否可以消除 "performSelector" 上的警告并接收 return 值或对象?
Is it possible to silence the warning on "performSelector" and receive the return value or object?
我熟悉此 ARC 警告的解决方案 (performSelector may cause a leak because its selector is unknown) 并且在大多数情况下都已实施,但我似乎无法找到正确获取 return 值的方法对于选择器而不仅仅是抑制警告。
好像不能或者不应该做,但是重写代码逻辑(别人开发的)太费时间了。
代码示例:
NSString *message = [callback performSelector:validatorSel withObject:textCell.textField.text];
如果已知 validatorSel
不以 alloc
或 new
开头,或者名称中包含 copy
(或 Copy
),并且您知道不涉及内存管理覆盖(这种情况很少见),那么这里的默认内存管理将是正确的,您可以使用适当的 #pragma
抑制警告。如果你不能证明这些事情,那么这可能会崩溃,这就是为什么会有警告。
如果你不能证明上面的要求,那么这个在ARC下是没有办法保证安全的。您将不得不在没有 ARC 的情况下构建它或重写它。
从您的代码示例来看,您似乎期待一个采用 NSText *
和 return 和 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 正确指出的那样,如果选择器没有 return 保留值,这仅在 ARC 下是安全的,即对于普通 [*] 选择器,如果它是 的成员init、copy 或 new 方法系列。现在你不太可能被传递给 validatorSel
的 init 系列方法,因为这需要 callback
成为对 alloc
的引用但不是 init
的对象,所以我们现在可以忽略它 [#]。要测试其他两个系列,您可以使用以下代码:
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 系列方法的 return 值...
处理复制和新系列方法
ARC 通过 属性 被放置在 method/function 类型上,知道方法或函数 return 是一个保留对象。 命名约定 只是语言推断属性的方式,如果它不存在,可以在 method/function 声明中使用 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 它将 return 一个保留的对象,ARC 将以与已知 copy[=75= 相同的方式处理调用] 或 新 系列方法。
HTH
注:处理init族方法
我们跳过了 init 系列,不仅因为它极不可能,而且因为它的行为不同 - init 系列方法 consume 调用它们的对象引用,也就是说,它们希望传递一个它们拥有所有权的拥有对象,并在需要时释放它。不出所料,使用参数也由属性指示,就像 returning 保留对象一样。好奇的 reader 可能希望确定所需的代码,即使需要它的可能性很小。
[*] "normal" 选择器是一种方法,它遵循 Objective-C 的标准命名约定,并且不使用属性以与标准约定相反的方式改变内存所有权行为.仅支持标准约定并不是一个很大的限制,约定的全部意义在于代码依赖于它们!
[#] 你当然也不太可能通过 new 系列选择器,callback
通常必须是对 class 对象,但处理它与 copy 系列相同,因此我们将其包括在内。
我熟悉此 ARC 警告的解决方案 (performSelector may cause a leak because its selector is unknown) 并且在大多数情况下都已实施,但我似乎无法找到正确获取 return 值的方法对于选择器而不仅仅是抑制警告。
好像不能或者不应该做,但是重写代码逻辑(别人开发的)太费时间了。
代码示例:
NSString *message = [callback performSelector:validatorSel withObject:textCell.textField.text];
如果已知 validatorSel
不以 alloc
或 new
开头,或者名称中包含 copy
(或 Copy
),并且您知道不涉及内存管理覆盖(这种情况很少见),那么这里的默认内存管理将是正确的,您可以使用适当的 #pragma
抑制警告。如果你不能证明这些事情,那么这可能会崩溃,这就是为什么会有警告。
如果你不能证明上面的要求,那么这个在ARC下是没有办法保证安全的。您将不得不在没有 ARC 的情况下构建它或重写它。
从您的代码示例来看,您似乎期待一个采用 NSText *
和 return 和 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 正确指出的那样,如果选择器没有 return 保留值,这仅在 ARC 下是安全的,即对于普通 [*] 选择器,如果它是 的成员init、copy 或 new 方法系列。现在你不太可能被传递给 validatorSel
的 init 系列方法,因为这需要 callback
成为对 alloc
的引用但不是 init
的对象,所以我们现在可以忽略它 [#]。要测试其他两个系列,您可以使用以下代码:
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 系列方法的 return 值...
处理复制和新系列方法
ARC 通过 属性 被放置在 method/function 类型上,知道方法或函数 return 是一个保留对象。 命名约定 只是语言推断属性的方式,如果它不存在,可以在 method/function 声明中使用 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 它将 return 一个保留的对象,ARC 将以与已知 copy[=75= 相同的方式处理调用] 或 新 系列方法。
HTH
注:处理init族方法
我们跳过了 init 系列,不仅因为它极不可能,而且因为它的行为不同 - init 系列方法 consume 调用它们的对象引用,也就是说,它们希望传递一个它们拥有所有权的拥有对象,并在需要时释放它。不出所料,使用参数也由属性指示,就像 returning 保留对象一样。好奇的 reader 可能希望确定所需的代码,即使需要它的可能性很小。
[*] "normal" 选择器是一种方法,它遵循 Objective-C 的标准命名约定,并且不使用属性以与标准约定相反的方式改变内存所有权行为.仅支持标准约定并不是一个很大的限制,约定的全部意义在于代码依赖于它们!
[#] 你当然也不太可能通过 new 系列选择器,callback
通常必须是对 class 对象,但处理它与 copy 系列相同,因此我们将其包括在内。