22

I'm helping on an iOS project with lots of methods and definitions common to many different classes in the AppDelegate. So, in each of those classes, in the .h file, I use #import "AppDelegate.h". This works fine until I need access to one of those classes that already imports the AppDelegate into another class that imports AppDelegate. At this point, I get a Duplicate Interface Definition error for AppDelegate.

Ok, so that seems fair. I'm already importing AppDelegate into a file that I'm importing, so AppDelegate is getting imported from two different places. So I remove the AppDelegate line, and everything is fine.

But what happens when I need to import two classes that both need to import AppDelegate?

I have a very specific problem that I'm trying to wrap my head around, and I know it is being caused by something that has to do with this, but I'm not sure what. So I'm hoping if I figure out how I'm supposed to be handling this sort of importing, and sort everything else out, and hope that this solves my problem. So to put this in more concrete terms:

I have ClassA.h, ClassB.h, and ClassC.h. All have #import "AppDelegate.h". When I need to use #import "ClassB.h" in ClassA, I remove the #import "AppDelegate.h" line from ClassA. Everything works smoothly. But what happens if I also need to #import "ClassC.h" into ClassA, and but ClassB and ClassC NEED to have the #import "AppDelegate.h"?

EDIT:

I tried the exact scenario I described above in a clean project, and it built fine, so there is something else at play. But what I can say with certainty is that when this issue came up previously with this project, it was a duplicate interface definition of AppDelegate, and when I removed the #import "AppDelegate.h" line, the error went away, and I still had access to the AppDelegate.h methods and enums through other imported files.

CowGoes
  • 309
  • 1
  • 2
  • 9
  • Are you sure you use `#import` and not `#include` ? `#import` is designed to never import the same header file twice, so it does not seem logical that the compiler #import "AppDelegate.h" twice – AliSoftware Sep 13 '12 at 22:38
  • 100% sure. My google research has said the same thing. I've had a similar issue in the past, which I was able to fix by including the file in the .m instead of the .h, but unfortunately, I need access to an enum in the imported file in the importing .h, so this is not an option. – CowGoes Sep 13 '12 at 22:47
  • 1
    But I just made a sample app with exactly the scenario I described at the bottom, and it worked. So I guess there is something else at play here. But what I can say with certainty is that when this issue came up in the past, it was a duplicate interface definition of AppDelegate, and when I removed the #import "AppDelegate.h" line, the error went away, and I still had access to the AppDelegate.h methods and enums through other imported files. – CowGoes Sep 13 '12 at 22:51
  • Write enum in separate *.h file and import them where you need. – ZGl6YXNt Sep 13 '12 at 22:53
  • But I also need to use methods in the AppDelegate. Should I import the AppDelegate in the .m file then? – CowGoes Sep 13 '12 at 22:56

6 Answers6

28

The best prevention and cure for this is to follow some guidelines on when to import from a header file. As a general rule, never import from an Objective-C header except in these cases:

  1. You need to extend a class declared in another header.
  2. You need to declare conformity with a protocol declared in another header.
  3. You need to refer to a non-class, non-protocol type defined in another header in the public methods and / or properties. To refer to protocols and classes, forward declare them with @class or @protocol, like @class ClassFromOtherHeader;

Every other #import should go in your implementation. My recommendation is to start moving all your #import statements out of headers and into the implementation files according to these rules. Start with the files you think are at the root of the problem and move outward. This will fix your problem and give you the side benefit of clearer code and faster build times.

Carl Veazey
  • 18,392
  • 8
  • 66
  • 81
  • Thank you for these sets of guidelines. They are definitely helpful to know. I went through and cleaned up the code, and in most cases, I was able to move a significant number of #imports into the .m. However, I was not able to remedy the problem entirely. Almost every class needs to import the AppDelegate.h and two other classes due to the need to define . Building resulted in the same duplicate interface definition errors popping up for the AppDelegate. It occurred to me that some of these files that import AppDelegate.h are imported into AppDelegate.m. Could this be the issue? – CowGoes Sep 14 '12 at 00:07
  • @CowGoes you're welcome, and it could be part of the problem. Also double check you're not using `#include` anywhere by mistake. I updated my answer to be more more specific about forward declaring - be ruthless with your forward declarations. Are you all using any version control where you could look through your changes and narrow down which particular import directive introduced the issue? – Carl Veazey Sep 14 '12 at 05:13
  • I actually just solved the problem- turns out that there actually WAS another AppDelegate.h included in the project. The guy who was working on this project before me copied things from other projects pretty indiscriminately I guess. But I guess it was a blessing in disguise, since now I know the proper protocol for importing in implementation vs header files. – CowGoes Sep 14 '12 at 05:22
  • @CowGoes oh, one of *those* engineers ;) Glad my answer helped, and good luck with the project! – Carl Veazey Sep 14 '12 at 05:25
  • Also make sure you are not importing a .m file LOL thats what happened to me. – vnchopra Mar 18 '17 at 03:36
  • 1
    Very helpful answer. Last four lines solved my issue. Surely deserve an upvote. – Aanchal Chaurasia Nov 23 '17 at 08:20
21

For me none of the above answers were helping, nor did the answer given here work.

What fixed it for me was closing Xcode, going to ~/Library/Developer/Xcode/DerivedData and deleting all of the derived data associated with this project. After that I reopened the project and it was working fine.

Hope that helps someone!

Community
  • 1
  • 1
poff
  • 1,640
  • 15
  • 16
  • 1
    Had the same issue, and this was the only solution that worked for me. The problem cropped up after moving a bunch of files around in Finder and then updating the Xcode project. – Jeremy White Aug 13 '14 at 17:29
  • That worked for me. I removed all of the files with the name myfile.o where myfile is the name of the .h file where the warning occurred: – Rick Schlueter Jul 02 '16 at 15:29
  • @poff, this reared its ugly head for my simple project on iOS 9 - and your fix still works. Thanks – user3741598 Feb 02 '18 at 01:53
3

In my case, none of the solutions mentioned fixed the issue. Xcode was reporting a duplicate interface for a class I rewrote in Swift. Somehow it kept pulling in the Objective-C header file for a class that wasn't directly referenced in the project.

I opened the Terminal, cd into the project directory, then ran the following to track down any files that were including the class header: grep -nr ProblemClassName.h .

It turned out that the bridging header included an obsolete file that wasn't even referenced in the project navigator. That in turn was importing the header files referenced in the Xcode error, that were also not included in the Xcode project navigator. Now I know to not rely only on the Xcode project navigator for files referenced by the error.

tl;dr Double check the bridging header to ensure that all files that are imported there should be there and are not importing headers that are in-turn importing the problem headers.

Andrew
  • 7,630
  • 3
  • 42
  • 51
1

I found that a project had a subproject and instead of referencing the includes in the subproject with the proper syntax:

#import <SubProject/Filename.h>

It was directly importing them

#import <Filename.h>

This was only possible because the path of the subproject was included in the "header search paths" of the main project - which is the wrong way to do business. So I deleted it from there. The subproject should copy the needed included files in its "build phases - copy files" section (which was already happening actually), and the proper form of import that uses the Subproject/Filename.h syntax should be used.

Andy Weinstein
  • 2,639
  • 3
  • 21
  • 32
0

Fwiw I started getting this seemingly at random - for me the fix was to do Product->Clean and it magically went away.

canhazbits
  • 1,664
  • 1
  • 14
  • 19
0

For me, I forgot to include parenthesis in interface definition in m file.

ahmad zen
  • 26
  • 1
  • 3