Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift class using Objective-C class using Swift class

I have an obj-c project to which I successfully added a new Swift class A, which is being used by some existing obj-c class B - the use of the automatically generated "MyProject-Swift.h" header worked as expected.

I also successfully added a new Swift class C that uses some existing obj-c class D - the use of the bridging header also worked as expected.

However, suppose I want to refer from my Swift class C to the existing obj-c class B (which in turn refers to the new Swift class A). In order to do that I need to import "B.h" to the bridging header. However, if I do that I get an error in class B: "'MyProject-Swift.h' file not found" (i.e., the file is no longer generated).

Am I doing something wrong or is this a kind of interaction between Swift and Objective-C that is not allowed? It looks like there is a kind of circular reference that the compiler is unable to solve.

--- EDIT ---

I'll try to make the question clearer by adding some code.

-- PREAMBLE --

I added a new Swift class to an obj-c project:

//  SwiftClassA.swift
import Foundation
@objc class SwiftClassA : NSObject {
    var myProperty = 0
}

The code compiles correctly and is translated into obj-c stubs in the automatically generated "MyProject-Swift.h" header like so:

// MyProject-Swift.h
...
SWIFT_CLASS("_TtC7MyProject11SwiftClassA")
@interface SwiftClassA : NSObject
@property (nonatomic) NSInteger myProperty;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

Now, one obj-c class uses SwiftClassA:

//  ObjCClass.h
#import <Foundation/Foundation.h>
#import <MyProject-Swift.h>
@interface ObjCClass : NSObject
@property (nonatomic, strong) SwiftClassA *aProperty;
@property (nonatomic) int *aNumber;
@end

This also works seamlessly.

-- THE QUESTION --

Can I now create a new Swift class that refers to the obj-c class (ObjCClass) that is using the Swift class SwiftClassA?

This is what I can't do.

If I add the new Swift class:

//  SwiftClassB.swift
import Foundation
@objc class SwiftClassB : NSObject {
    var aPropertyOfClassB = 1
    func someFunc() {
        var objCObject = ObjCClass()
        var theProperty = objCObject.aProperty
        print("The property is \(theProperty)")
    }
}

this of course won't compile because of "Use of unresolved identifier 'ObjCClass'". So I need to add that to the bridging header file:

//  BridgingHeader.h
#ifndef MyProject_BridgingHeader_h
#define MyProject_BridgingHeader_h
...
#import "ObjCClass.h"
#endif

However, if I do that, the ObjCClass.h file won't compile giving a "'MyProject-Swift.h' file not found".

I've read in several places (with no example, though) that this may mean that there is a circular reference and that a forward reference using @class could solve the problem. However, I'm not sure what needs to be forward referenced and where, and all my attempts failed.

I hope the question is no longer confusing now!

like image 526
Maiaux Avatar asked Jan 04 '15 01:01

Maiaux


People also ask

Can we use Swift class in Objective-C?

You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.

Can I use Swift library in Objective-C?

The Swift library cannot be directly called from Objective-C, since it is missing the required annotations in the code, and in many cases, modules do not inherit from NSObject, rather they use the native Swift data types.

How do you subclass a Swift class in Objective-C?

Unfortunately, it's not possible to subclass a Swift class in Objective-C. Straight from the docs: You cannot subclass a Swift class in Objective-C. See Apple's guide on interoperability for more details on what you can and cannot access with Objective-C.


1 Answers

This is a typical cyclical referencing problem.

Be careful to read the docs:

To avoid cyclical references, don’t import Swift into an Objective-C header file. Instead, you can forward declare a Swift class to use it in an Objective-C header. Note that you cannot subclass a Swift class in Objective-C.

So, you should use "forward declare" in .h, and #import in .m:

//  ObjCClass.h
#import <Foundation/Foundation.h>

@class SwiftClassA;

@interface ObjCClass : NSObject
@property (nonatomic, strong) SwiftClassA *aProperty;
@property (nonatomic) int *aNumber;
@end
// ObjCClass.m
#import "ObjCClass.h"
#import "MyProject-Swift.h"

@implementation ObjCClass
// your code
@end
like image 54
rintaro Avatar answered Oct 04 '22 03:10

rintaro