Accessing Swift protocol property implemented in an Obj-C class from another Swift class

I've seen lots of questions regarding implementing Obj-C protocols in Swift, but not so much the other way around, and I haven't seen this specifically.

I've seen lots of questions regarding implementing Obj-C protocols in Swift, but not so much the other way around, and I haven't seen this specifically.

I am using a mixed Obj-C / Swift codebase. I have a Swift protocol defined as follows:

NamedItem.swift

@objc protocol NamedItem {
    var name: String { get }
}

I have an existing Objective-C class that currently has its own name property:

MyObjcClass.h

@interface MyObjcClass : NSObject
@property (nonatomic, strong, readonly) NSString* name;
@end

I have a couple other classes that have a name property, so obviously I'd like to associate them all with a protocol instead of typecasting to a bunch of different types. Now, if I try to switch my Obj-C class from having its own property to implementing the Swift protocol:

MyObjcClass.h

@protocol MyObjcProtocol
@property (nonatomic, strong, readonly) NSString* place;
@end

@interface MyObjcClass : NSObject
@end

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

@implementation MyObjcClass
@synthesize name = _name;
@synthesize place = _place;
@end

This works great, in my other Objective-C classes, but if I try to access the name property from a Swift class:

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.name // error
myObj.place // no problem

I get the following error:

Value of type 'MyObjcClass' has no member 'name'

If I don't remove the existing @property declaration from MyObjcClass.h and omit the @synthesizestatement everything builds correctly. Which seems weird and wrong - If you adopt a Objc-C protocol from an Obj-C class you don't have to re-define the property, just the @synthesize statement is sufficient.

I've tried defining the Swift protocol about every way I could think of and have been able to find suggestions about, but I haven't been able to get around this.

So, what is the correct way to implement a Swift protocol property (maybe specifically a read-only property?) in an Objective-C class such that another Swift class can access it? Do I really have to re-declare the property in the Obj-C header? I know I could always give it up and just define the protocol in Objective-C, but... Swift is the future! (or something like that...)

How to use Objective C Cocoapods in Swift Framework

My swift framework has dependency of Objective C Framework. How do I use that ?

My swift framework has dependency of Objective C Framework. How do I use that ?

When I try to use Bridging Header, I am getting error like Framework Target doesn't support Bridging Header

After my search , I found answers for

  1. How to use Objective C Files in Swift Framework
  2. How to use Objective C Framework with swift project

But I need solution for

How to use Objective C Framework as dependency in Swift Framework ?

Thanks in advance :)

A guide to Object Detection with OpenCV and Swift

A guide to Object Detection with OpenCV and Swift

In this article, we’ll see how to create and launch a object detection algorithm using OpenCV and Swift

Swift has been with us for a while now, and through its iterations, it has brought to us all the features of a modern object-oriented programming language. These include optionals, generics, tuples, structs that support methods, extensions and protocols, and many more. But if your application relies on a library that’s written using C++ then you can’t count on Swift anymore. Luckily Objective-C++ is here to help us.

Since its introduction, Swift has had great interoperability with Objective-C and we will use Objective-C for bridging Swift with C++. Objective-C++ is nothing more than Objective-C with the ability to link with C++ code, and using that, in this blog post, we will create a simple app that will recognize the Toptal logo inside the image using OpenCV. When we detect that logo, we’ll open the Toptal home page.

As stated on the OpenCV web page:

"OpenCV was designed for computational efficiency and with a strong focus on real-time applications. Written in optimized C/C++, the library can take advantage of multi-core processing."
This is a great solution if you want fast to develop and reliable computer vision.

Creating the OpenCV Objective-C++ Wrapper

In this tutorial, we will design the application which will match a Toptal logo inside an image and open Toptal web page. To begin, create a new Xcode project and set up CocoaPods using pod init. Add OpenCV to Podfile pod 'OpenCV and run pod install in Terminal. Be sure to uncomment use_frameworks! statement inside Podfile.

Now, when we have OpenCV inside Xcode project, we have to connect it with Swift. Here is a quick outline of the steps involved:

Step 1: Create a new Objective-C class OpenCVWrapper. When Xcode asks you “Would you like to configure an Objective-C bridging header?” choose “Create bridging header.” The bridging header is the place where you import Objective-C classes, and then they are visible inside Swift.

Step 2: In order to use C++ inside Objective-C, we have to change the file extension from OpenCVWrapper.m to OpenCVWrapper.mm. You can do it by simply renaming the file inside Xcode’s project navigator. Adding .mm as an extension will change the file type from Objective-C to Objective-C++.

Step 3: Import OpenCV into OpenCVWrapper.mm using the following import. It’s important to write the given import above #import "OpenCVWrapper.h" because this way we avoid a well-known BOOL conflict. OpenCV contains enum that has the value NO which causes a conflict with the Objective-C BOOL NO value. If you don’t need classes that use such enum, then this is the simplest way. Otherwise, you have to undefine BOOL before importing OpenCV.

#ifdef __cplusplus 
 
#import <opencv2/opencv.hpp> 
 
#import <opencv2/imgcodecs/ios.h> 
 
#import <opencv2/videoio/cap_ios.h> 
 
#endif

Step 4: Add #import "OpenCVWrapper.h" to your bridging header.

Open OpenCVWrapper.mm and create a private interface where we will declare private properties:

@interface OpenCVWrapper() <CvVideoCameraDelegate>
 
@property (strong, nonatomic) CvVideoCamera *videoCamera;
 
@property (assign, nonatomic) cv::Mat logoSample;
 
@end

In order to create CvVideoCamera, we have to pass UIImageView to it, and we will do that through our designator initializer.

- (instancetype)initWithParentView:(UIImageView *)parentView delegate:(id<OpenCVWrapperDelegate>)delegate {
 
   
 
    if (self = [super init]) {
 
        self.delegate = delegate;
 
       
 
        parentView.contentMode = UIViewContentModeScaleAspectFill;
 
       
 
        self.videoCamera = [[CvVideoCamera alloc] initWithParentView:parentView];
 
        self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
 
        self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh;
 
        self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
 
        self.videoCamera.defaultFPS = 30;
 
        self.videoCamera.grayscaleMode = [NSNumber numberWithInt:0].boolValue;
 
        self.videoCamera.delegate = self;
 
       
 
        // Convert UIImage to Mat and store greyscale version
 
        UIImage *templateImage = [UIImage imageNamed:@"toptal"];
 
        cv::Mat templateMat;
 
        UIImageToMat(templateImage, templateMat);
 
        cv::Mat grayscaleMat;
 
        cv::cvtColor(templateMat, grayscaleMat, CV_RGB2GRAY);
 
        self.logoSample = grayscaleMat;
 
       
 
        [self.videoCamera start];
 
    }
 
    return self;
 
}

Inside it, we configure CvVideoCamera that renders video inside the given parentView and through delegate sends us cv::Mat image for analysis.

processImage: method is from CvVideoCameraDelegate protocol, and inside it, we will do template matching.

- (void)processImage:(cv::Mat&)image {
 
   
 
    cv::Mat gimg;
 
   
 
    // Convert incoming img to greyscale to match template
 
    cv::cvtColor(image, gimg, CV_BGR2GRAY);
 
   
 
    // Get matching
 
    cv::Mat res(image.rows-self.logoSample.rows+1, self.logoSample.cols-self.logoSample.cols+1, CV_32FC1);
 
    cv::matchTemplate(gimg, self.logoSample, res, CV_TM_CCOEFF_NORMED);
 
    cv::threshold(res, res, 0.5, 1., CV_THRESH_TOZERO);
 
   
 
    double minval, maxval, threshold = 0.9;
 
    cv::Point minloc, maxloc;
 
    cv::minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);
 
   
 
    // Call delegate if match is good enough
 
    if (maxval >= threshold)
 
    {
 
        // Draw a rectangle for confirmation
 
        cv::rectangle(image, maxloc, cv::Point(maxloc.x + self.logoSample.cols, maxloc.y + self.logoSample.rows), CV_RGB(0,255,0), 2);
 
        cv::floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(.1), cv::Scalar(1.));
 
       
 
        [self.delegate openCVWrapperDidMatchImage:self];
 
    }
 
}

First, we convert the given image to grayscale image because inside the init method we converted our Toptal logo template matching image to grayscale. Next step is to check for matches with a certain threshold which will help us with scaling and angles. We have to check for angles because you can capture a photo in various angles in which we still want to detect logo. After reaching the given threshold we will invoke delegate and open Toptal’s web page.

Don’t forget to add NSCameraUsageDescription to your Info.plist otherwise, your application will crash right after calling [self.videoCamera start];.

Now Finally Swift

So far we were focusing on Objective-C++ because all the logic is done inside it. Our Swift code will be fairly simple:

  1. Inside ViewController.swift, create UIImageView where CvVideoCamera will render content.
  2. Create an instance of OpenCVWrapper and pass the UIImageView instance to it.
  3. Implement OpenCVWrapperDelegate protocol to open Toptal’s web page when we detect the logo.
class ViewController: UIViewController {
 
   
 
    var wrapper: OpenCVWrapper!
 
   
 
    @IBOutlet var imageView: UIImageView!
 
    override func viewDidLoad() {
 
        super.viewDidLoad()
 
        // Do any additional setup after loading the view, typically from a nib.
 
   
 
        wrapper = OpenCVWrapper.init(parentView: imageView, delegate: self)
 
    }
 
}
 
extension ViewController: OpenCVWrapperDelegate {
 
    //MARK: - OpenCVWrapperDelegate
 
   
 
    func openCVWrapperDidMatchImage(_ wrapper: OpenCVWrapper) {
 
        UIApplication.shared.open(URL.init(string: "https://toptal.com")!, options: [:], completionHandler: nil)
 
    }
 
}

OpenCV Swift in Action

In this article, we have shown how you can integrate C++ code with Swift and create wrapper classes that are here for bridging C++ code with Swift. Now, when we detect the Toptal Logo through the camera, we open Toptal’s home page.

For future updates, you may want to run CV template matching in a background thread. This way, you won’t block the main thread and the UI will stay responsive. Because this is a simple example of OpenCV, template matching may not be extra successful, but the purpose of this article was to show you how you can start using it.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about OpenCV and Python

Complete Python Bootcamp: Go from zero to hero in Python 3

Machine Learning A-Z™: Hands-On Python & R In Data Science

Python and Django Full Stack Web Developer Bootcamp

Computer Vision Using OpenCV

OpenCV Python Tutorial - Computer Vision With OpenCV In Python

Python Tutorial: Image processing with Python (Using OpenCV)

A guide to Face Detection in Python

Machine Learning Tutorial - Image Processing using Python, OpenCV, Keras and TensorFlow

Face Detection using Open-CV

Passing a Swift protocol to an Objective-C pointer

<em>Using XCode 10.1 / Swift 4.2.</em>

Using XCode 10.1 / Swift 4.2.

I'm trying to assign an object that conforms to a Swift protocol to an Objective-C pointer. The following code is a minimal example that compiles and works as expected, but it gives me the following warnings:

If assigning to a local variable: Incompatible pointer types initializing 'NSObject<Animal> *__strong' with an expression of type 'id<Animal> _Nullable'

If assigning to a stored property: Incompatible pointer types assigning to 'NSObject<Animal> *' from 'id<Animal> _Nullable'

Any idea on how to address that warning without just silencing it?

Swift code:

@objc protocol Animal {
    var name: String { get }
}

@objc class Pig: NSObject, Animal {
var name: String = "pig"
}

@objc class Cow: NSObject, Animal {
var name: String = "cow"
}

@objc class Farm: NSObject {
static func getAnimal(name: String) -> Animal? {
// return some animal or nil
}
}

Objective-C code:

// This code returns a valid pointer to a Pig object
// that is usable in objective-c, but it also triggers
// the warning described above
NSObject<Animal>* animal = [Farm getAnimalWithName:@"pig"];