Xcode: Get rid of forward class warning - objective-c

In Xcode, I have a forward class declared so as to avoid a circular import e.g.
#class MyClass;
And then I do a method call on that class e.g.
[MyClass myMethod];
But I get a forward class warning e.g.
warning: receiver 'MyClass' is a
forward class and corresponding
#interface may not exist
How can I hide those across my whole project?

You use forward class declarations in your header file to prevent circular imports.
You must still import the MyClass header in your .m file. The circular import problem doesn't exist with .m files.

My answer to a similar question may be of use here.
The basic concept is this:
use #class in header files, and then use #import in the .m files.

Related

Objective C interface generated header can't be imported in other header

I am not an Obj C pro, but I should write some code in Objective C and bridge a Swift code to it.
I success in importing the Generated Header to the .m file:
#import "<my_module>-Swift.h"
But when I try importing the same header to the .h file it throws this error:
BTW, I only want to add a public variable that instances from a Swift class to a specific obj c class. I've tried to put these lines at the .h and .m files:
#property (nonatomic, readwrite, strong) Card *card;
What should I do?
In your case, since all you need to do is declare a property of type Card*, you don't actually need to import the header—you can just forward-declare the class with #class Card; before using it.
If you want to reference a Swift class in an Objective-C header, you cannot #import the *-Swift.h file, but should rather use a forward declaration as described in https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html, see the section titled Referencing a Swift Class or Protocol in an Objective-C Header. This is basically what #jtbandes is suggesting in the comment.
One gotcha here: the Swift class you want to use in Objective-C must extend the NSObject class, directly or indirectly.

How to prevent circular reference when Swift bridging header imports a file that imports Hopscotch-Swift.h itself

I am integrating Swift into a large existing Objective C project and have run into what I think is a circular reference.
The classes in question are as follows:
Objective C Controller
#import "Hopscotch-Swift.h"
#interface MyController : UIViewController<MyProtocol>
...
#end
Swift Protocol
#objc protocol MyProtocol: NSObjectProtocol {
...
}
Bridging Header
#import "MyController.h"
This code fails to compile because the Hopscotch-Swift.h file will not generate.
I think this is due to a circular reference error as I can import Hopscotch-Swift.h into objective c headers that are not included in Hopscotch-Bridging-Header.h and it works fine.
Is there a workaround for this issue or should I file a radar with Apple?
Forward declaration should work, in your case.
In your .h:
#protocol MyProtocol;
#interface MyController : UIViewController<MyProtocol>
#end
In your .m:
#import "HopScotch-Swift.h"
From How can I add forward class references used in the -Swift.h header? and the Swift interoperability guide:
If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.
I ran into this when trying to use Swift classes inside Objective-C protocols, where the protocol was also implemented by another Swift class. It reeked of circular references and I guessed that it might be a problem trying to circularly generate the bridging headers, rather than a 'normal' circular include problem.
The solution, for me, was to just use forward declarations before the protocol declaration:-
// don't include the MyProject-Swift.h header
// forward declaration of Swift classes used
#class SwiftClass;
#protocol MyProtocol <NSObject>
- (SwiftClass *)swiftClass;
#end
The forward declaration by itself didn't work for me. It compiled without errors but still had warnings that the protocol couldn't be found. I treat all warnings as errors, so this isn't good enough.
I was able to fix it by moving the protocol implementation into another category header.
So here's what worked for me:
In my MyOtherSwiftFile.swift:
#objc protocol MyProtocol: class {
func viewController(didFinishEditing viewController: MyViewController)
}
In my MyViewController.h:
#interface MyViewController // Removed protocol implementation declaration here
#end
Added MyViewController+MyProtocol.h to project, and put this in there:
#interface MyViewController (MyProtocol) <MyProtocol>
#end
The methods themselves can stay where they are if you want.
After you implement the above and compile, you'll get compiler warning(s) somewhere in your code that requires that MyViewController implements MyProtocol. In that file, you will #import "MyViewController+MyProtocol.h"
Alternatively you can convert your protocol to an Objective-C protocol MyProtocol.h and then use it in Swift by including MyProtocol.h in your bridging header.
You could something like this in the .h file you suspect to trigger the circular reference:
#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

Using extern #class in order to add a category?

Is there a way to "promise that a class exists elsewhere" (i.e. similar to the extern keyword) and therefore avoid having to use #import statements?
Here is an example of what I am trying to do:
extern #class MyClass;
#interface Foo : NSObject
#property (nonatomic) MyClass *abc;
#end
Where MyClass definitely exists and is used throughout my program, but at the time I create this file, I don't know the name of the file where MyClass is defined.
Update: It seems like the error is related to the fact that this is a category. Updated code follows:
#class MyClass;
#interface MyClass (Extensions)
- (void)foo;
#end
Gives the following error:
Cannot define category for undefined class 'MyClass'.
You can "forward declare" a class by simply doing:
#class MyClass;
When you actually go to use the class though, you will still need to import the header.
However, you must use an import when subclassing or adding a category for the class. The compiler must be able to see the real class in order to modify or extend it.
Your only option to "extend" a class that you can't import directly into a file would be to modify the class at runtime using the objective-c runtime library. You could create another class and then add the methods from that class to the real class at runtime.
Basically you would use NSClassFromString to get the class and then use class_addMethod to add those methods to the real class.
This is almost certainly overkill for anything you would want to do though.
Yes, that's exactly what the #class directive is for (without the extern part).

Circular Importing of ViewController

In Appdelegate I am Importing Some Class for showing the view and in that view I have required to import the Same AppDelegate for accessing some method and variable but when I am doing this. Its shows circular import error.
I have tried by importing by #class in .h file and import in .m file.
In both classes you should only use #class in the .h file and then add the #import in the .m file. This is the correct solution for the problem you describe.
Note that the circularity could be bigger because a 3rd class could be #imported and it in turn #imports another class to make the circular link. Generally you should use #class in your .h files unless you have to #import (for the superclass and #protocols you implement).

"Cannot find interface declaration error..." after #class

I've run into an Objective-C problem that doesn't seem to make any sense to me. I am a relatively well-versed ObjC programmer and understand the whole "forward declaration" concept, but this one has me scratching my head. So here's the deal:
ClassA is a class in my Xcode project that is project-only.
ClassB is a subclass of ClassA which is public and is imported into my framework's header.
I am getting a "Cannot find interface declaration for 'ClassA', superclass of 'ClassB'..." error when building. I have already put the #class ClassA; forward declaration in ClassB.h, but that does not seem to solve the problem. When I change the #class ClassA; to #import ClassA.h, it works fine. However, since ClassA is project-only, dependent projects cannot build ClassB because it cannot access ClassA's source.
Any help would be appreciated and I hope that makes sense. Thanks!
The problem is that you have an infinite loop in your #imports.
The solution: all #imports go in the implementation file and all classes needed are declared in the .h files.
To subclass a class, the superclass's full declaration must be available to the compiler. #class just enables references to instances of said class -- allows for A *foo;.
Subclassing requires more metadata (at least, it did under the legacy runtime -- I think it might be possible to support subclassing without the full super's #interface. Technically possible, but probably not useful.)
I have an answer: You must check your '#import' order. Before you use the superclass it should be imported and compiled.
I had an issue where I was using categories in a superclass method and was getting this inheritance error. Once I moved the categories .h imports to the superclass .m file thing started getting better.
Just carry out all possible headers from .h to .m file of superclass and see which one is the matter of the problem. I'm sure that it's one of common headers used in both classes.
Like #Igor said, the order of imports matters:
I had to change
#import <KeychainItemWrapper/KeychainItemWrapper.h>
#import <Foundation/Foundation.h>
to
#import <Foundation/Foundation.h>
#import <KeychainItemWrapper/KeychainItemWrapper.h>