7
votes

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!

1
I don't think this question is ill-posed or unclear, and the problem is real and of real interest (to me, at least). I'm not against downvoting, but could you please at least tell me what's wrong with this question? If it's a duplicate, where is the duplicate? If it's too evident, what is the answer? ThanksMaiaux
In its current form, the question is very confusing.Lord Zsolt
This question seems reasonable to me.Jack Lawrence

1 Answers

12
votes

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