1

Now I'm adding Swift code on objective-C based iOS application.

But I have a problem in calling the objective-C method from Swift side.

I'd like to get and draw image on UIImageView in View or ViewController which is written with Swift. On the other hand my wrapper class of Photos Library is written with objective-C.

My wrapper class of Photos Library is below.

・MyPhotoLibraryMgr.h

typedef void (^AppPhotoLibraryGetImageCompletion)(UIImage *image, NSError *error);

- (void)getImageWithTarget:(NSInteger)index
                targetSize:(CGSize)targetSize
                completion:(AppPhotoLibraryGetImageCompletion)completion;

・MyPhotoLibraryMgr.m

- (void)getImageWithTarget:(NSInteger)index
                targetSize:(CGSize)targetSize
                completion:
(AppPhotoLibraryGetImageCompletion)completion
{
    PHAsset *asset = _myAsetsList[index];

    PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
    options.resizeMode = PHImageRequestOptionsResizeModeFast;
    options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;

    [[PHImageManager defaultManager] requestImageForAsset:asset
                                               targetSize:targetSize
                                              contentMode:PHImageContentModeAspectFill
                                                  options:options
                                            resultHandler:^(UIImage *result, NSDictionary *info) {
                                                NSError *error = [info objectForKey:PHImageErrorKey];
                                                if (error) {
                                                    NSLog(@"error=%@", error);
                                                }
                                                completion(result, error);
                                            }];
}

I can get and draw image in View or ViewController written by objective-C like below,

・MyViewController.m

AppPhotoLibraryMgr *photoLibMgr = [AppPhotoLibraryMgr sharedInstance];
AppPhotoLibraryGetImageCompletion completion = ^(UIImage *image, NSError *error) {
                imageView.image = image;
};

[[AppPhotoLibraryMgr sharedInstance] getImageWithTarget:index
                                             targetSize:imageView.frame.size
                                             completion:completion];

But I can't get image in View or ViewController written in Swift.

・MySwiftViewController.swift

let completion = {(image: UIImage, error: NSError) -> AppPhotoLibraryGetImageCompletion in
    let imageView = UIImageView(image: image)
}

photoLibMgr?.getImageWithTarget(index, targetSize: size, completion: completion)

Error message from Xcode is


Cannot convert value of type 'UIImage, NSError -> AppPhotoLibraryGetImageCompletion" to expected argument type 'AppPhotoLibraryGetImageCompletion'

D4ttatraya
  • 3,344
  • 1
  • 28
  • 50
M.Masa
  • 532
  • 4
  • 20

3 Answers3

3

Your declaration of completion variable is wrong in MySwiftViewController.swift file.
Edit it like this:

let completion: AppPhotoLibraryGetImageCompletion = { (image, error) in
   let imageView = UIImageView(image: image)
}

OR
If you don't want to declare completion handler as variable, then simply do the:

LinphoneLoginController.shared().getImageWithTarget(index, targetSize: size) { (image, error) in
    let imageView = UIImageView(image: image)
}
D4ttatraya
  • 3,344
  • 1
  • 28
  • 50
  • I could get images with the declaration of `completion` you suggested. Thank you very much. – M.Masa Jul 05 '17 at 10:05
2

The block typedef void (^AppPhotoLibraryGetImageCompletion)(UIImage *image, NSError *error); in objective-c has return type void.

But the counter part in your Swift has return type other than Void. The completion block should be like:

let completion = {(image: UIImage, error: NSError) -> Void in
    ...
    ...
}

Use typealias for making your closure reusable.

Example:

typealias AppPhotoLibraryGetImageCompletion = (UIImage, NSError) -> Void

let completion: AppPhotoLibraryGetImageCompletion = { (image, error) in
    ...
    ...
}

Edit: Different way

photoLibMgr?.getImageWithTarget(index, targetSize: size, completion: { (image, error) in
    ...
    ...
})
nayem
  • 7,285
  • 1
  • 33
  • 51
  • Thanks for your advice. I tried your `typealias` but the error occurred with the message **_Cannot convert value of type '(UIImage, NSError) -> Void' to expected argument type 'AppPhotoLibraryGetImageCompletion!'_** – M.Masa Jul 05 '17 at 08:43
  • Can you try the different way that I just added? Don't use typealias and don't declare `completion` property. – nayem Jul 05 '17 at 09:00
  • I could get images with your **Edit: Different way**. Thank you very much. – M.Masa Jul 05 '17 at 10:04
  • Well, but seems you've accepted other answer. Basically the accepted answer and my answer are pretty much same. – nayem Jul 05 '17 at 11:05
-1

It should be typedef instead of Typedef. Move typedef on top of interface declare and don't declare it again:

typedef void (^AppPhotoLibraryGetImageCompletion)(UIImage *image, NSError *error);

@interface MyPhotoLibraryMgr....

After the changes it should work similar in Swift, auto complete will change your AppPhotoLibraryGetImageCompletion to (image, error) {..}

Tj3n
  • 9,837
  • 2
  • 24
  • 35
  • Thanks. It was just a mistake of coping my code. In my code don't use capital 'T' and don't declare the typedef again in interface. And the error code is the same. I cannot work my code with the same error. – M.Masa Jul 05 '17 at 05:46
  • hmm...it shouldnt be any problem, try build your code again then only write the part in Swift, the suggestion may show `AppPhotoLibraryGetImageCompletion` but after press enter then it will be correct – Tj3n Jul 05 '17 at 06:01
  • Thank you for your reply. I cleaned once and then start "Run" on Xcode. But the result didn't change. I got the same error. – M.Masa Jul 05 '17 at 08:39