mikep mikep - 4 months ago 17
Swift Question

Call method with function as argument of Cocoa Touch Framework (swift) from Single View Application (objective-c)

I created

Cocoa Touch Framework
in
swift
(called MyFramework). In MyFramework I have method which requires functions as arguments. In short hand MyFramework contains this code:

public class MyFramework : NSObject {
public func MyMethod(successCallback : (String) -> Void, errorCallback : (String, String) -> Void) -> Void {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// successCallback("some value");
// errorCallback("error reason", "error message");
});
}
}


I can include
MyFramework
in
Single View Application
called
MyAppSwift
(in
swift
) and successfully call MyMethod of MyFramework in
ViewController.swift
by this code:

class ViewController: UIViewController {
let myframework : MyFramework = MyFramework();

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myframework.MyMethod(self.onSuccess, errorCallback : self.onError);
}

private func onSuccess(value : String) {
// ...
}

private func onError(reason : String, error : String) {
// ...
}
}


I can include
MyFramework
in
Single View Application
called
MyAppObjectiveC
(in objective-c) but I do not know how to call
MyMethod
of MyFramework in
ViewController.m
...

// In ViewController.h

#import <UIKit/UIKit.h>
#import <MyFramework/MyFramework.h>
@interface ViewController : UIViewController {

}
@property (strong, nonatomic) MyFramework * myframework;
- (void) onSuccess : (NSString *) value;
- (void) onError : (NSString *) reason : (NSString *) error;
@end


.

// In ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void) viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myframework = [[MyFramework alloc] init];
[self.myframework MyMethod : self onSuccess, self onError];
}
- (void) onSuccess : (NSString *) value {
// ...
}
- (void) onError : (NSString *) reason : (NSString *) error {
// ...
}

@end


This line [self.myframework MyMethod : self onSuccess, self onError]; is not working. Xcode says expecting identifier ":" after onSuccess and then expects expresion. Im not sure what to insert. I read several answers on stackoverflow how to pass method as argument in objective-c but no success. For example I have tried selectors [self.myframework MyMethod : @selector(onSuccess:), @selector(onError::)]; but Xcode says: "Sending 'SEL' to parameter of incompatible type 'void(^_Nonnull)(NSString * _Nonnull __strong)'

Answer

As you pointed out, according to the *-Swift.hheader Swift's MyMethod is imported into Objective-C as taking blocks as arguments. So, you need to pass it blocks that wrap the Objective-C method calls, something like this:

[self.myframework MyMethod: ^ (NSString * s){ [self onSuccess:s]; }
       errorCallback: ^(NSString * s1, NSString * s2) { [self onError:s1 reason:s2]; }];

See here for more info about Objective-C blocks: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html