IOS Dev
IOS Dev

Reputation: 286

Setting a closure as a variable in Swift and trying to call from Objective C class

I defined a variable as a closure in Swift Class. My code works fine when variable is called from Swift class. But variable is not accessible from Objective C class. Other functions I am able to call though.

    @objc class IAPHelper: NSObject {
    static let shared = IAPHelper()
    var purchaseStatusBlock: ((IAPHelperAlertType) -> Void)?  
     }

    called from a swift class 
    IAPHelper.shared.purchaseStatusBlock = {[weak self] (type) in
                guard let strongSelf = self else{ return }
                if type == .purchased {
                   // show an alert
                }
            } 

    I tried to call variable purchaseStatusBlock from Objective C class  
    IAPHelper.shared.purchaseStatusBlock ,
    Compiler Error :Property 'purchaseStatusBlock' not found on object of type 'IAPHelper *'

Here is my Objective C code:

#import "VMedu-Swift.h"
@interface FreeSubscriptionController ()
{ 
}
- (void)viewDidLoad {
    [super viewDidLoad];

UIButton *restoreBtn = [VMEduUtil roundBtnWithFrame:CGRectMake(hmBtn.frame.origin.x-20, hmBtn.frame.origin.y+10, 70, searchImg.size.height) title:@"Restore" cornerRadius:3 backgroundColor:[UIColor clearColor] target:IAPHelper.shared action:@selector(restorePurchase)];
    restoreBtn.tintColor = [UIColor whiteColor];
    [topBarView addSubview:restoreBtn];

  IAPHelper.shared.purchaseStatusBlock  ..... shows me error
}

@end

Another Swift Class PurchaseSubscriptionController which uses same closure variable purchaseStatusBlock works well. Here is my code

  override func viewDidLoad() {
        super.viewDidLoad()

      IAPHelper.shared.fetchAvailableProducts()
        IAPHelper.shared.purchaseStatusBlock = {[weak self] (type) in
            guard let strongSelf = self else{ return }
            if type == .purchased {
                let alertView = UIAlertController(title: "", message: type.message(), preferredStyle: .alert)
                let action = UIAlertAction(title: "OK", style: .default, handler: { (alert) in

                    print("product purchased")
                })
                alertView.addAction(action)
                strongSelf.present(alertView, animated: true, completion: nil)
            }
        }
    }

Upvotes: 1

Views: 2696

Answers (2)

OOPer
OOPer

Reputation: 47896

Seems you just need to explicitly annotate some properties and types with @objc:

@objc public enum IAPHelperAlertType: Int {
    case disabled
    case restored
    case purchased
    func message() -> String{
        switch self {
        case .disabled:
            return "Purchases are disabled in your device!"
        case .restored:
            return "You've successfully restored your purchase!"
        case .purchased:
            return "You've successfully bought this purchase!"

        }
    }
}

(Added :Int as suggested by Xcode.)

class IAPHelper: NSObject {
    @objc static let shared = IAPHelper()
    @objc var purchaseStatusBlock: (@convention(block) (IAPHelperAlertType) -> Void)?
}

(Added two @objc and @convention(block). @convention(block) makes the closure type compatible with Objective-C blocks.)

With these changes above, you can write something like this in your Objective-C code:

    IAPHelper.shared.purchaseStatusBlock(IAPHelperAlertTypeDisabled)

Upvotes: 3

Reinier Melian
Reinier Melian

Reputation: 20804

You are using wrong Objective-C Code

add a @objc in your enum declaration

@objc
enum IAPHelperAlertType : Int{
    case aaaa
    case bbbb
}

Replace this

IAPHelper.shared.purchaseStatusBlock  ..... shows me error

with this

[[IAPHelper shared] setPurchaseStatusBlock:^(NSInteger inte) {
        NSLog(@"test");
    }];

Upvotes: 4

Related Questions