Call swift code from objc code in objc project

I read the article here... https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c

and this is what I did.


  1. Created a header file for swift file.
  2. added @class SwiftFile.h
  3. #import MyAppTargetName-Swift.h in the objc file from where I want to reference my swift code.

Now in my swift file when I write...


@interface ClassName
{
MySwiftClass *swiftClass;
}

I get error message Unknown Type Name "MySwiftClass".


How can I resolve this and get going?

Am I doing something wrong?

Does the bridging header i created along with the swift file need to me edited?


Neerav

Accepted Reply

I’m honestly not sure how you managed to get into the state you’ve got into. It’s hard to debug such problems without having access to your project. As an alternative, I’ve included working instructions below. Please try repeating this at your end. That’ll help in one of two ways:

  • If they don’t work, there’s something wonky in your environment.

  • If they do work, you have a working example that you can compare against your main project.

Here’s what I did:

  1. In Xcode 11.3, I created a new app from the macOS > App template. I named it MyApp, set the language to Objective-C, and the UI to Storyboard.

  2. In the Project navigation on the left, I selected

    main.m
    and then chose File > New > File.
  3. I selected the macOS > Swift template and named the file

    MySwiftClass.swift
    .
  4. After saving the file, Xcode asked me whether I wanted to create a bridging header. I clicked Create Bridging Header. This isn’t necessary for this task, but you’ll likely need it later and it’s best to do it at this point.

  5. I change

    MySwiftClass.swift
    to look like this:
    import Foundation
    
    
    @objc
    class MySwiftClass: NSObject {
    
    
    @objc
    func run() {
        print("MySwiftClass.run \(Date())")
    }
    }

    .

  6. In the Project navigation on the left, I selected

    main.m
    again.
  7. I added this line after the existing

    #import
    :
    #import "MyApp-Swift.h"

    .

  8. Inside the

    @autoreleasepool
    I added this code:
    MySwiftClass * obj = [[MySwiftClass alloc] init];
    [obj run];

    .

  9. I ran the app. It printed:

    MySwiftClass.run 2020-02-20 10:37:03 +0000

    .

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

The bridging header generated is empty by default.

Do you realize you posted this in the Objective-C forum rather than the Swift forum?

I would post 'call obj c code from swift code' in the swift forum. Being centered around objc, I eould suppose things working with objc would be best posted in obj c forum

Did you declare

MySwiftClass
as
@objc
?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Here are the steps i took after reading your last answer and the article on importing swift code into objective.


  1. created a header file for swift fle
  2. included @class className in it
  3. included #import "AppName-Swift.h"
  4. Compiler gave error saying swift language version needs to be set in build settings. rectified it.

No w I get unknown type name on trying to define a pointer to the swift class.

do i need to reference the class in swift from my objective c .m file or should i using objc code itself.

I’m honestly not sure how you managed to get into the state you’ve got into. It’s hard to debug such problems without having access to your project. As an alternative, I’ve included working instructions below. Please try repeating this at your end. That’ll help in one of two ways:

  • If they don’t work, there’s something wonky in your environment.

  • If they do work, you have a working example that you can compare against your main project.

Here’s what I did:

  1. In Xcode 11.3, I created a new app from the macOS > App template. I named it MyApp, set the language to Objective-C, and the UI to Storyboard.

  2. In the Project navigation on the left, I selected

    main.m
    and then chose File > New > File.
  3. I selected the macOS > Swift template and named the file

    MySwiftClass.swift
    .
  4. After saving the file, Xcode asked me whether I wanted to create a bridging header. I clicked Create Bridging Header. This isn’t necessary for this task, but you’ll likely need it later and it’s best to do it at this point.

  5. I change

    MySwiftClass.swift
    to look like this:
    import Foundation
    
    
    @objc
    class MySwiftClass: NSObject {
    
    
    @objc
    func run() {
        print("MySwiftClass.run \(Date())")
    }
    }

    .

  6. In the Project navigation on the left, I selected

    main.m
    again.
  7. I added this line after the existing

    #import
    :
    #import "MyApp-Swift.h"

    .

  8. Inside the

    @autoreleasepool
    I added this code:
    MySwiftClass * obj = [[MySwiftClass alloc] init];
    [obj run];

    .

  9. I ran the app. It printed:

    MySwiftClass.run 2020-02-20 10:37:03 +0000

    .

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Except for adding objc to the function call also (which i didnt make a call to yet), I did the same thing.


Now xcode is giving me a different error.


where I have written


MySwiftClass *ptr;
ptr = [[MySwiftClass allo]init];

I get errory saying no init found. here is my class...


//
//  StoreObserver.swift
//  Step Goals
//
//  Created by Neerav Kothari on 18/02/20.
//  Copyright © 2020 Neerav Kothari. All rights reserved.
//

import Foundation
import StoreKit

@objc class StoreObserver: NSObject, SKPaymentTransactionObserver {

    //Initialize the store observer.
    @objc override init() {
        super.init()
        //Other initialization here.
    }

    //Observe transaction updates.
    @objc func paymentQueue(_ queue: SKPaymentQueue,updatedTransactions transactions: [SKPaymentTransaction]) {
        //Handle transaction states here.
    }

}


This code is actually from a in-app purchase documentation which has a bug and it wont load the objc code.


Now what can I do so that it finds init.


I dont know swift.

You need a "c" in

ptr = [[MySwiftClass allo]init];


ptr = [[MySwiftClass alloc] init];


You should be able to find code that implements IAP written in Objective C.

It's alloc only. That was a type in the post.

I did the same thing.

Did you actually run through my steps?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Did you actually run through my steps?

Sorry, that wasn’t clear. What I should’ve said was…

Did you run through my steps and create a new project? If so, did it also fail?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I truely appreciate your effort. I already had a new project ready since. I think it's some sort of compiler bug showing weird errors. When it was showing error for -Swift.h file not found, closing and reopeaning xcode solved the problem. Realising I am loosing a lot of time on this, I coded the file in objc, reverse engineering the swift code. However, I'll need it to work as there is more documentation i need that's only loading in swift. Would importing it in AppDelegate make a difference instead main.h?

I’m not quite sure how to parse this. Are you saying that:

  • If you create a new project, it works? And thus the problem only affects your main project?

  • Or that, even if you follow the above instructions, your new project still fails?

This matters because it tells us whether there’s a general problem or a specific problem with your main project.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Even in the new. By the time I read your post I was already on a new project for a different reason.