Objective-C equivalent to Java's anonymous cla

2019-01-18 03:17发布

问题:

I want to set the delegate of an object inside a class method in Objective-C. Pseudo-code:

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

In Java I would simply create an anonymous class that implemented the delegate protocol. How can I do something similar in Objective-C?

Basically I would like to avoid creating a separate class (and files) to implement a simple delegate protocol.

回答1:

There are currently no anonymous classes in Objective-C.

Often you can use an already existing object. For instance, for an NSTableViewDataSource, you can implement the methods in the document or view controller and pass that as the delegate.

Or you can have the object itself implement the protocol and make it its own delegate in the default case.

Or the methods that send the delegate messages can check for a nil delegate and do something sensible in that situation.

Or you can declare and define a class inside the implementation file you are creating the object that needs a delegate.



回答2:

As JeremyP has rightly said, There are no anonymous classes in Objective C like there are in Java.

But in Java, anonymous classes are mostly used to implement single method interface or what we also call as a functional interface.

We do it to avoid having to implement the interface** in a class **just for one method implementation which is most commonly used for Listeners, Observers and event handlers.

This is mostly done because of **lack of anonymous first class functions in Java (prior to version 8 and project lambda).

Objective C has something called as blocks, where you can directly pass a block which contains the implementation of that single method rather than an empty class wrapping it up.

Example:

A use of Anonymous Class in 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
                              }
                         });

In Objective 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
                                            }];


回答3:

Anonymous classes can be implemented with library. Several months ago I have worked on MMMutableMethods fork to improve old implementation (discussing with author) and to add my own mechanism without any obj-c runtime manipulation.

https://github.com/k06a/MMMutableMethods

A. First mechanism works on obj-c runtime class creation:

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. Second mechanism works on simple message forward implementation:

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);
           }];
})

First one creates new obc-j classes in runtime, it allows you to create classes MM_CREATE_CLASS(MM_REUSE, *) and directly instances with MM_CREATE(MM_REUSE, *). Classes will be created only on first execution and reused by default, but you can avoid reusing by calling MM_CREATE_CLASS_ALWAYS(*) and MM_CREATE_ALWAYS(*).

The second mechanism doesn't creates any runtime instances, just remember blocks for selectors and forward method calls to them.

I prefere second way not to create a lot of classes in runtime. IMHO it is much safer and enough powerful.

To use this library just:

pod 'MMMutableMethods', :git => 'https://github.com/k06a/MMMutableMethods'