我想在Objective-C中的类方法中设置对象的委托。伪代码:
+ (ClassWithDelegate*) myStaticMethod {
if (myObject == nil) {
myObject = [[ClassWithDelegate alloc] init];
// myObject.delegate = ?
}
return myObject;
}
在Java中,我只需创建一个实现委托协议的匿名类。如何在Objective-C中做类似的事情?
基本上我想避免创建一个单独的类(和文件)来实现一个简单的委托协议。
答案 0 :(得分:19)
正如JeremyP正确地说的那样,目标C中没有像Java中那样的匿名类。
但在Java中,匿名类主要用于实现单个方法接口或我们也称为功能接口。
我们这样做是为了避免在类**中实现接口**只是为了一个最常用于监听器,观察者和事件处理程序的方法实现。
这主要是因为在Java中缺少匿名的第一类函数(之前的版本8和项目lambda )。
Objective C有一个叫做块的东西,你可以直接传递一个包含该单个方法实现的块,而不是一个包含它的空类。
示例:
在Java中使用匿名类
//Functional interface
interface SomethingHandler
{
void handle(Object argument);
}
//a method that accepts the handler in some other class
class SomeOtherClass
{
void doSomethingWithCompletionHandler(SomethingHandler h){
// do the work that may consume some time in a separate thread may be.
// when work is done call the handler with the result which could be any object
h.handler(result);
};
}
// Somewhere else in some other class, in some other code
// passing the handler after instantiating someObj as an object of SomeOtherClass which can use the handler as needed
SomeOtherClass someObj = new SomeOtherClass();
someObj.doSomethingWithCompletionHandler( new SomethingHandler()
{
void handle(Object argument)
{
// handle the event using the argument
}
});
在目标C
// declare the handler block
typedef void (^SomethingHandler)(id argument){}
// this interface is different than Java interface which are similar to Protocols
@interface SomeOtherClass
-(void)doSomethingWithCompletionHandler:(SomethingHandler)h;
@end
@implementation SomeOtherClass
-(void)doSomethingWithCompletionHandler:(SomethingHandler)h
{
// do the work that may consume some time in a separate thread may be.
// when work is done call the handler with the result which could be any object
h(result);
}
@end
// passing the handler after instantiating someObj as an object of SomeOtherClass which can use the handler as needed
SomeOtherClass* someObj = [[SomeOtherClass alloc] init]; // ARC :)
[someObj doSomethingWithCompletionHandler:^(id argument)
{
// handle the event using the argument
}];
答案 1 :(得分:14)
Objective-C目前没有匿名类。
通常您可以使用已存在的对象。例如,对于NSTableViewDataSource,您可以在文档或视图控制器中实现这些方法,并将其作为委托传递。
或者你可以让对象本身实现协议,并在默认情况下使其成为自己的委托。
或者发送委托消息的方法可以检查nil委托,并在那种情况下做一些合理的事情。
或者您可以在创建需要委托的对象的实现文件中声明和定义一个类。
答案 2 :(得分:1)
可以使用库实现匿名类。几个月前,我一直致力于MMMutableMethods
fork来改进旧的实现(与作者讨论)并添加我自己的机制,而不需要任何对象的运行时操作。
https://github.com/k06a/MMMutableMethods
一个。第一种机制适用于obj-c运行时类创建:
MM_CREATE(MM_REUSE,^(Class class){
[class addMethod:@selector(onResultWithId:)
fromProtocol:@protocol(AMCommandCallback)
blockImp:^(id this,id res){
NSLog(@"onResultWithId: %@",res);
}];
[class addMethod:@selector(onErrorWithJavaLangException:)
fromProtocol:@protocol(AMCommandCallback)
blockImp:^(id this,JavaLangException *e){
NSLog(@"onErrorWithJavaLangException: %@",e);
}];
})
B中。第二种机制适用于简单的消息转发实现:
MM_ANON(^(MMAnonymousClass *anon){
[anon addMethod:@selector(onResultWithId:)
fromProtocol:@protocol(AMCommandCallback)
blockImp:^(id this,id res){
NSLog(@"onResultWithId: %@",res);
}];
[anon addMethod:@selector(onErrorWithJavaLangException:)
fromProtocol:@protocol(AMCommandCallback)
blockImp:^(id this,JavaLangException *e){
NSLog(@"onErrorWithJavaLangException: %@",e);
}];
})
第一个在运行时创建新的obc-j类,它允许您使用MM_CREATE_CLASS(MM_REUSE, *)
创建类MM_CREATE(MM_REUSE, *)
和直接实例。只有在第一次执行时才会创建类,默认情况下会重复使用,但您可以通过调用MM_CREATE_CLASS_ALWAYS(*)
和MM_CREATE_ALWAYS(*)
来避免重复使用。
第二种机制不会创建任何运行时实例,只需记住选择器的块和对它们的转发方法调用。
我更喜欢第二种方式,不要在运行时创建很多类。恕我直言,它更安全,更强大。
仅使用此库:
pod 'MMMutableMethods', :git => 'https://github.com/k06a/MMMutableMethods'