Быстрый обратный вызов от Objective-C - PullRequest
0 голосов
/ 05 июля 2018

В приложении Swift у меня есть ViewController, который вызывает новый modal. Эта modal имеет ViewController Objective-C реализацию как ViewController_obj_c.

Это modal показано из кода Swift, и я хочу вызвать свойство обратного вызова (с параметром UIImage), когда код Objective-C сделан.

Моя функция обратного вызова "signCompleteCallback" не работает. Как я могу заполнить свойство обратного вызова из Swift и вызвать его внутри Objective-C?

SwiftViewController.swift:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showModalSegue" {
        if let nextVC = segue.destination as? ViewController_obj_c {

            nextVC.signCompleteCallback = #selector(self.Test)
        }
    }
}

@objc func Test(image: UIImage)
{
    debugPrint("Test method was called as callback with image parameter")
}

ViewController_obj_c.h:

@interface ViewController_obj_c : UIViewController <UIPopoverPresentationControllerDelegate>


@property SEL signCompleteCallback;

- (IBAction)Done_Clicked:(id)sender;

ViewController_obj_c.m:

- (IBAction)Done_Clicked:(UIButton *)sender
{
    UIGraphicsBeginImageContext(_dV.bounds.size);
    [_dV.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

   [self signCompleteCallback]; // Here is the point when I want to call me callback and as a parameter i want to send image
}

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Почему бы вам не использовать Objective-C block ?

SwiftViewController.swift:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showModalSegue" {
        if let nextVC = segue.destination as? ViewController_obj_c {

            nextVC.signCompleteCallback = testMethod(image:) //`(image:)` is not needed when not ambiguous
        }
    }
}

func testMethod(image: UIImage) {
    debugPrint("Test method was called as callback with image parameter")
}

ViewController_obj_c.h:

@interface ViewController_obj_c : UIViewController<UIPopoverPresentationControllerDelegate>

typedef void (^signCompleteCallbackType)(UIImage * _Nonnull image); //Declare the block type

@property signCompleteCallbackType signCompleteCallback; //Declare the block property using the block type

- (IBAction)Done_Clicked:(id)sender;

@end

ViewController_obj_c.m:

- (IBAction)Done_Clicked:(UIButton *)sender
{
    UIGraphicsBeginImageContext(_dV.bounds.size);
    [_dV.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    self.signCompleteCallback(image);    //Use the block just like a normal function
}
0 голосов
/ 06 июля 2018

Я нашел одно решение, но я не доволен им.

Если кто-то даст лучшее решение, я буду рад за него. В этом решении мне не нравится создавать новый протокол, который я должен наследовать в части Swift (создать новый класс или наследовать его в существующем SwiftViewcontroller, не имеет значения)

Один из способов - создать @protocol внутри Objective-C:

@protocol ObjC_ManagerDelegate 
-(void) signCallBack: (UIImage *)image;
@end

ViewController_obj_c.h:

@interface ViewController_obj_c : UIViewController <UIPopoverPresentationControllerDelegate>

    @property (nonatomic, strong) id <ObjC_ManagerDelegate>delegate;

    - (IBAction)Done_Clicked:(id)sender;
@end

ViewController_obj_c.m:

- (IBAction)Done_Clicked:(UIButton *)sender
{
    UIGraphicsBeginImageContext(_dV.bounds.size);
    [_dV.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [self.delegate signCallBack:image];
}

И часть Swift выглядит так. Создайте новый класс и унаследуйте его от ObjC_ManagerDelegate:

class SwiftmanagerDelegate: ObjC_ManagerDelegate {
    func signCallBack(_ image: UIImage!) {
        // do something
    } 
}

и, наконец, заполнить новый класс в качестве делегата

SwiftViewController.swift:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showModalSegue" {
        if let nextVC = segue.destination as? ViewController_obj_c {

            nextVC.delegate = SwiftmanagerDelegate()
        }
    }
}
...