Maiaux
Maiaux

Reputation: 975

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!

Upvotes: 7

Views: 2582

Answers (1)

rintaro
rintaro

Reputation: 51911

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

Upvotes: 12

Related Questions