Barterio
Barterio

Reputation: 720

Java like interface in Objective C

I'm trying to start working on iOS development with Objective-c. I have a lot of experience with Java, so I try to do things in a Java way. Please help me to understand the correct way to code in Objective C.

I have the following interface in Java:

public interface MyInterface {
  void onSuccess(String successString);
  void onError(String errorMessage);
}

I will use it like this:

public static void main(String... args){
    MyInterface interface = new MyInterface() {
        @Override
        public void onSuccess(String successMessage) {
            // things happen here
        }

        @Override
        public void onError(String errorMessage) {

        }
    };
}

How do I convert this code to Objective C? I need to create an interface and pass an instance of this interface to another C method.

I've tried blocks(^), but it is acceptable only when I need to pass an object with only one callback. What is my approach to pass an object with two callback functions to a method?

Upvotes: 0

Views: 129

Answers (2)

Amin Negm-Awad
Amin Negm-Awad

Reputation: 16660

Your code is basically an example of delegation in Objective-C. You build it in two (or three, depends on how you want to count it) in Objective-C:

First, you create a protocol. Usually the delegating instance is passed as argument. This is for convenience reasons in some situation. So let's imagine a class Delegator.

@protocol MyDelegate
- (void)delegator(Delegator*)delegator didFinishWithSuccess:(NSString*)message;
- (void)delegator(Delegator*)delegator didFinishWithError:(NSString*)message;
@end

In Objective-C such a protocol is and only is a contract without any content. You add the content by creating a class that adopts the protocol (hence the contract):

@interface MyDelegate : NSObject < MyDelegate >
@end // You do not need to redeclare the methods.

@implementation MyDelegate
- (void)delegator(Delegator*)delegator didFinishWithSuccess:(NSString*)message
{
  …
}
- (void)delegator(Delegator*)delegator didFinishWithError:(NSString*)message
{
  …
}
@end

Then you can simply create an instance and pass it as delegate:

…
MyDelegate delegate = [MyDelegate new]; 
[delegator doSomethingWithDelegate:delegate];

The delegator stores its delegate and send appropriate messages to the delegate.

Upvotes: 1

CRD
CRD

Reputation: 53000

I have only one *void argument that i can pass as a handle, so i need to pass two blocks in one object reference

One way is to define a class with two instance variables of block type, one each for the success and error cases; an initialiser which takes values (blocks) and sets those instance variables; and two instance methods, one each for success and failure cases, which simply invoke the block referenced by the corresponding instance variable.

If you need the interface as other classes will implement it directly just make your new class conform to it as well.

Another way is to define your class with two block-valued properties, and use property references to obtain the blocks rather than methods to invoke them.

The tricky part comes when you pass your class instance as a void * and later cast it back to use the methods/properties. If you are using ARC you need to use a bridging cast in both directions and ensure your object stays alive until needed. You can achieve this by using a cast at the call site which transfers ownership of the object away from ARC, thus preventing ARC from releasing it; and a cast at the use site which transfers ownership back to ARC, so that after the appropriate method/property has been called ARC will clean up the object. You'll need to read up on bridging casts to do this; they are no more complicated to write than ordinary casts but you do need to understand the semantics.

Of course at this point, especially after manual memory management with bridging casts, you might decide to switch to a more Objective-C oriented model from your Java one. However the above is a standard technique for dealing with C functions which follow the void * context pointer model, and there is nothing wrong per se in using it when required.

HTH

Upvotes: 1

Related Questions