【问题标题】:Objective-C equivalent to Java's anonymous classes in class methodsObjective-C 等价于 Java 在类方法中的匿名类
【发布时间】:2010-09-22 14:39:04
【问题描述】:

我想在 Objective-C 的类方法中设置对象的委托。伪代码:

+ (ClassWithDelegate*) myStaticMethod {
    if (myObject == nil) {
        myObject = [[ClassWithDelegate alloc] init];
        // myObject.delegate = ?
    }
    return myObject;
}

在 Java 中,我将简单地创建一个实现委托协议的匿名类。如何在 Objective-C 中做类似的事情?

基本上我想避免创建一个单独的类(和文件)来实现一个简单的委托协议。

【问题讨论】:

  • @Dave DeLong 澄清标题以区别于该问题。在这种情况下,上下文是一个静态方法。
  • 上下文无关紧要。您必须提供一个对象 (id) 作为委托,而另一个问题很清楚地回答了 Objective-C 中没有匿名类之类的东西(还没有),所以您将不得不使用普通对象。
  • Objective-C 中没有静态方法。有实例消息和类消息。
  • @Dave DeLong 我的问题很可能措辞不佳,但我不认为它们是同一个问题。是的,Obj-C 中没有匿名类。但我的问题是:在 Obj-C 类消息中,匿名类允许我在 Java 静态方法中做什么的最佳方式是什么?

标签: java objective-c delegates anonymous-types


【解决方案1】:

正如 JeremyP 所说,Objective 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
                                            }];

【讨论】:

    【解决方案2】:

    Objective-C 目前没有匿名类。

    通常您可以使用已经存在的对象。例如,对于 NSTableViewDataSource,您可以实现文档或视图控制器中的方法并将其作为委托传递。

    或者您可以让对象本身实现协议并在默认情况下使其成为自己的委托。

    或者发送委托消息的方法可以检查 nil 委托并在这种情况下做一些明智的事情。

    或者您可以在实现文件中声明和定义一个类,您正在创建需要委托的对象。

    【讨论】:

    • 感谢 JeremyP!所以基本上在这种情况下,我可以在实现文件中定义一个临时类,在类消息中创建一个实例并将其分配为委托。对吗?
    【解决方案3】:

    匿名类可以用库来实现。几个月前,我致力于MMMutableMethods fork 以改进旧的实现(与作者讨论)并添加我自己的机制,而无需任何 obj-c 运行时操作。

    https://github.com/k06a/MMMutableMethods

    A.第一种机制适用于 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'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多