Imagine I have two header files: SomeFileA.h and SomeFileB.h
SomeFileA.h includes SomeFileB.h, and SomeFileB.h includes SomeFileA.h.
This creates a loop and confuse the compiler. How can we overcome this?
You should "forward declare" your classes. This tells the compiler that the class exists, but without the need to actually import it.
SomeFileA.h
#class SomeFileB // <-- This "forward declares SomeFileB"
#interface SomeFileA
#property (nonatomic, strong) SomeFileB *someFileB;
...
#end
SomeFileA.m
#import "SomeFileB.h"
#implementation SomeFileA
...
#end
And the same thing, but the other way around in SomeFileB
SomeFileB.h
#class SomeFileA // <-- This "forward declares SomeFileA"
#interface SomeFileB
#property (nonatomic, strong) SomeFileA *someFileA;
...
#end
SomeFileB.m
#import "SomeFileA.h"
#implementation SomeFileB
...
#end
If you don't use a class in the header, you don't need to forward declare it.
#interface SomeFileA
//I took out the property for SomeFileB.. no need for the #class anymore.
...
#end
Related
I want to connect two classes of mine and link each other with a property of each class. I broke down the main aspects to this example:
Ocean.h file:
#import <Foundation/Foundation.h>
#import "Fish.h"
#interface Ocean : NSObject
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
Fish.h file:
#import <Foundation/Foundation.h>
#import "Ocean.h"
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean; // Compiler: "Unknown type name Ocean"
#property (nonatomic) int age;
#end
What I wanna do in the end, is to manipulate the age property of an Fish object and be able to save it (listOfFishesInOcean, NSUserDefaults), as well as call a function in the Ocean object, when saving is completed. This way I'd always have the latest list of Fish-objects in my list of the Ocean-object.
My two problems here are:
How to avoid the import-loop, which causes the complier error, I think?
How should I implement the save & action workflow in the end?
I thought about solving this issue with notifications and observer but this way I'd still need to filter the notifications in any way, due to the fact that I've multiple Oceans with more Fishes.
Another idea to solve it, would be to give each Ocean object and Fish object an ID, which I would use as a key in NSUserDefaults again.
If anyone has some thoughts about it or other ideas, you are very welcome!
Import ".h" files only in ".m" file, like:
Ocean.h file:
#import <Foundation/Foundation.h>
#class Fish;
#interface Ocean : NSObject
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
Ocean.m file:
#import "Ocean.h"
#import "Fish.h"
#implementation Ocean
#end
Fish.h file:
#import <Foundation/Foundation.h>
#class Ocean;
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean;
#property (nonatomic) int age;
#end
Fish.m file:
#import "Fish.h"
#import "Ocean.h"
#implementation Fish
#end
I think one of the best approaches could be using the identifiers so you improve the performance.
#interface Ocean : NSObject
#property (nonatomic) int identifier;
#property (nonatomic) NSArray *listOfFishesInOcean;
#end
#interface Fish : NSObject
#property (nonatomic) int age;
#property (nonatomic) int parent_identifier;
#end
if you want to keep your approach:
#import <Foundation/Foundation.h>
#class Ocean;
#interface Fish : NSObject
#property (nonatomic) Ocean *homeOcean; // Compiler: "Unknown type name Ocean"
#property (nonatomic) int age;
#end
Fish.m
#import "Ocean.h"
This question already has answers here:
Errors when making circular reference imports
(2 answers)
Closed 8 years ago.
I have two custom NSObjects which reference each other, as below:
.h file class 1
#import <Foundation/Foundation.h>
#import "MyChildClass.h"
#interface MyParentClass : NSObject
#property (nonatomic, strong) NSString *Name;
#property (nonatomic) MyChildClass *myChild;
#end
.m file class 1:
#import "MyParentClass.h"
#implementation MyParentClass
#end
and...
.h file class 2:
#import <Foundation/Foundation.h>
#import "MyParentClass.h"
#interface MyChildClass : NSObject
#property (nonatomic) MyParentClass *myParent;
#end
.m file class 2:
#import "MyChildClass.h"
#implementation MyChildClass
#end
When I try and implement those as below, the project will not build, with the error "Arc Restrictions: Implicit conversion of an Objective-C pointer to 'int *' is disallowed with ARC"
View Controller implementation code:
MyParentClass *newParent = [[MyParentClass alloc] init];
MyChildClass *newChild = [[MyChildClass alloc] init];
newParent.Name = #"Johnny";
newParent.myChild = newChild;
newChild.myParent = newParent;
However, when I nest a second example into single .h/.m files, the project will build:
Nested .h file:
#import <Foundation/Foundation.h>
#class MyNestedClass;
#interface MyChildNestedClass : NSObject
#property (nonatomic, strong) MyNestedClass *myNested;
#property (nonatomic, strong) NSString *ChildName;
#end
#interface MyNestedClass : NSObject
#property (nonatomic, strong) MyChildNestedClass *myChild;
#property (nonatomic, strong) NSString *ParentName;
#end
Nested .m file:
#import "MyNestedClass.h"
#implementation MyChildNestedClass
#end
#implementation MyNestedClass
#end
I guess that by nesting the objects into a single file, I am somehow tricking ARC and that really I shouldn't be creating these circular references.
Could anyone suggest the correct way of nesting types like this?
What I am trying to achieve, is the following pseudo-scenario: Parent has a property of Child. Child has a property of the parent it is the child of.
Am I finding this difficult because I'm not supposed to do it (circular referencing), or am I missing something glaringly obvious?
Many thanks!
Do not #import "MyChildClass.h" in the parent class' header file, change it to
#class MyChildClass
and add the #import in the source file (.m)
I am trying to declare a property
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UIViewController
{
#property (nonatomic, strong) MPMoviePlayerController*player;
}
#end
I receive a red warning sign when i click on it, it reads;
a parameter list without types is only allowed in function definition
properties are outside of braces
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UIViewController
{
// here is for ivars only
id _something;
}
// properties and methods
#property (nonatomic, strong) MPMoviePlayerController*player;
#end
//Super class .h file
#interface MySuperClass : NSObject
#end
//Super class .m file
#interface MySuperClass ()
#property (nonatomic, strong) UITextField *emailField;
#end
#implementation MySuperClass
-(void)accessMyEmailField {
NSLog(#"My super email: %#", self.emailField.text);
}
#end
// ********** my subclass *******
//Subclass .h file
#interface MySubClass : MySuperClass
#end
//SubClass .m file
#interface MySubClass ()
#end
#implementation MySubClass
-(void)myEmail {
NSLog(#"My subclass email: %#", self.emailField.text);
}
-(void)setMyEmailFromSubclass{
self.emailField.Text = #"email#gmail.com"
}
#end
How do i access emailField in -(void)myEmail method.
How do i set email in Subclass -(void)setMyEmailFromSubclass; , and access it in super class accessMyEmailField
You can put accessors to these properties in a second header file, and import that file on a 'need-to-know' basis..
eg
mySuperClass+undocumentedProperties.h
#import "mySuperClass.h"
#interface mySuperClass(undocumentedProperties)
#property (nonatomic, strong) UITextField *emailField;
#end
mySuperClass.m
#import "mySuperClass+undocumentedProperties.h"
#interface mySuperClass()
///stuff that truly will be private to this class only
// self.emailField is no longer declared here..
#end
#implementation mySuperClass
#synthesize emailField; //(not really needed anymore)
/// etc, all your code unaltered
#end
mySubclass.h
#import "mySuperClass.h"
#interface mySubclass:mySuperClass
///some stuff
#end
mySubclass.m
#import "mySubclass.h"
#import "mySuperClass+undocumentedProperties.h"
#implementation
//off you go, this class is now 'aware' of this secret inherited property..
#end
obviously MySuperClass.m will have to import this .h file as well as its default one (or actually instead of, the default one is built in to this one), but your subclasses can import it too (directly into their .m file, so these properties remain private to the class. This is not a proper category because there is no corresponding mySuperClass+undocumentedProperties.m file (if you tried that you could not synthesize the backing iVars for these secret properties. Enjoy :)
Copy the private interface portion of the methods you want from your superclass - or in other words, in your Subclass.m file you would put:
#interface MySuperClass ()
#property (nonatomic, strong) UITextField *emailField;
#end
( place it above the existing #interface MySubClass () code )
Now your subclass knows that method exists in the superclass and can use it, but you are not exposing it to anyone else.
The whole point of private properties is exactly that and you should not want to access them. Because they are private they can change or be removed thus breaking the subclass that relies on them.
That being said they are not really private, just not "published". The can be called because Objective-C is a run-time dynamic language.
I am running an ARC 'refactor' on an old iOS app.
However, I am getting the following error
Receiver type 'WarningCallback' for instance message is a forward declaration
WarningCallback.h
#class WarningCallback;
#import <UIKit/UIKit.h>
#import "WebViewController.h"
#import "Constants.h"
#protocol WarningCallback
-(void) warningDismissedAndNavigateToCall:(BOOL) navigateToCall;
#end
#interface WarningViewController : WebViewController {
}
#property (nonatomic,retain) WarningCallback* parentVC;
#end
WarningCallback.m
#import "WarningViewController.h"
#implementation WarningViewController
#synthesize parentVC;
...
-(IBAction) done:(id) sender {
[[self parentVC] warningDismissedAndNavigateToCall:NO];
}
#end
The error occurs on the following line of WarningCallback.m
[[self parentVC] warningDismissedAndNavigateToCall:NO];
The error is because of the line #class WarningCallback;. The error message means that the compiler found a forward declaration of WarningCallback, but is not able to find the corresponding implementation. That's because WarningCallback is not a class, but a protocol.
If you want to forward declare a protocol you can do so as follows:
#protocol WarningCallback;
#interface WarningViewController : WebViewController
#property (nonatomic, weak) id<WarningCallback> parentVC;
#end
#protocol WarningCallback
- (void)warningDismissedAndNavigateToCall:(BOOL) navigateToCall;
#end
Note how I've declared parentVC.
Remove the line:
#class WarningCallback;
When declaring a #protocol, it is not necessary to also declare it as a #class unless you have a specific reason to do so. See:
What's with the declare a class and declare a protocol with the same name?