我正在尝试在Objective-C
中实现一个简单的观察者/监听器模式。
我有两个NSMutableArray
一个正在收听的不同类。这些都是通用类型(id
)。我还有一个数组,其中包含不同类的名称(NSStrings
)。
如何获取泛型类型,强制转换回原始类并向该类发送消息?
我尝试过这样的事情,但没有成功:
// _observers_type contains the names for the classes, _observers are the generic types.
- (void)notifyObservers;
{
for (int i = 0; i < [_observers count]; i++) {
NSString *classNameStr = [_observers_type objectAtIndex:i];
Class theClass = NSClassFromString(classNameStr);
(theClass)[[_observers objectAtIndex:i] triggerNotify];
}
}
另请注意,这些方法不是实例方法。我想用这种模式更新视图等。
答案 0 :(得分:1)
没有必要强制转换 - 实际上在这种情况下你不能强制转换,因为你有一个类对象,而不是一个类型,所以没有什么可以强制转换。
相反,只需发送消息。
如果从发送消息中收到编译时错误,则表示您尚未导入任何声明该方法的标头。只需导入具有该方法的类或协议的标头。
答案 1 :(得分:1)
您可以向声明为id的对象发送消息。
for (id object in observers)
[object triggerNotify];
您只能对编译时已知的类型使用强制类型转换,因此您正在执行的操作无法正常工作且无法工作。但是你可以向id发送任何消息 - 只需确保id实际响应消息。所以写
是安全的for (id object in observers)
if ([object respondsToSelector:@selector (triggerNotify)])
[object triggerNotify];
存储类的名称是没有意义的,因为如果你想知道类,你可以使用[object class]。
答案 2 :(得分:0)
试试此代码
for (int i = 0; i < [_observers count]; i++) {
[[_observers objectAtIndex:i] performSelector:@selector(triggerNotify)];
}
theClass在运行时进行评估,因此编译此行
(theClass)[[_observers objectAtIndex:i] triggerNotify];
与此相同的信息
[[_observers objectAtIndex:i] triggerNotify];
并且它将生成错误“没有已知的选择器实例方法'triggerNotify'”。
调用此
[[_observers objectAtIndex:i] performSelector:@selector(triggerNotify)];
向接收者发送相同的消息但不询问编译器是否可能。
答案 3 :(得分:0)
根据您的代码,您的所有类都会响应选择器triggerNotify
,因此您应该只能在所有对象上调用它而不会出现问题:
[[_observers objectAtIndex:i] triggerNotify];
应该没有必要对此进行强制转换。只要方法triggerNotify
存在于某个类的某个地方,编译器就不应该抱怨你正在调用它。
编辑:
根据您对我的回答的评论,您很可能不会在此代码所在的类中从任何实现此方法的类中导入标头。因此,如果您只是为实现此目的的类导入标头,它应该可以工作。否则,您可以使用另一个使用performSelector:
的答案中的建议,这样即使选择器不存在于任何地方也可以编译。
但是,为了尽可能安全,您应该在调用performSelector:
之前检查对象是否先响应选择器:
if ([[_observers objectAtIndex:i] respondsToSelector:@selector(triggerNotify)])