objective c circular reference [duplicate] - ios

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)

Related

Objective C - Avoid Import Loop

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"

ios/objective-c/core-data: How to show relationship as property in NSManagedObjects

I have two entities and have just created a 1:1 relationship between them. There are subclasses for the entities but they have a lot of code in them at this point so I don't want to use Xcode to automatically generate new NSManagedObject subclasses.
Instead, I thought I could just reference the relationship with a property in each one. I did that and it seemed to work for a while but now it is throwing mysterious errors and I can't seem to get rid of them. I have imported the reciprocal of each one but it is not helping. Can anyone recommend what I should do? Many thanks in advance.
Subclassed NSManagedObjects (simplified)
//Items.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Notes.h"
#interface Items : NSManagedObject
#property (nonatomic, retain) NSNumber *iid;
#property (nonatomic, retain) NSString *item;
//this is relationship
#property (nonatomic, retain) Notes *note;
//above throws error Unkown Type Name 'Notes'
#end
//Notes.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Items.h"
#interface Notes : NSManagedObject
#property (nonatomic, retain) NSNumber * nid;
#property (nonatomic, retain) NSString * note;
//this is relationship
#property (nonatomic, retain) Items *item;
//above throws error Unkown Type Name 'Item'
#end
This is similar to relationship
In Objective-C you can't use a type before it is declared. To fix this you can use a forward declaration of your classes by putting these lines below the #import statements and above the first #interface.
#class Items;
#class Notes;
If your posted code is not representative of your actual file structure (which I assume it isn't), you'll have to put the #class statement for Items in the Notes.h file and the #class statement for Notes in the Items.h file.

How to overcome a #import loop?

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

Xcode Don't recognize Object anymore

I have an object named friend (I know, first letter should be uppercase). I use this class in many other classes and view controller.
All of a sudden, without changing ANY CODE, every custom object I have, stopped recognize each other. I always get the error Unknown type name "friend".
I already tried to clear the project and restart the mac.
WTF is wrong with this Xcode? All of a sudden my whole project stops working.
Here is my class currentUser.h
#import <Foundation/Foundation.h>
#import "friend.h"
#interface currentUser : NSObject<NSCoding>
{
BOOL fromfacebook;
#private
NSMutableArray *upLoadStack;
}
#property (nonatomic,strong)NSString *token;
#property (nonatomic,strong)NSString *email;
#property (nonatomic,strong)NSString *name;
#property (nonatomic,strong)UIImage *userImg;
#property (nonatomic,strong)NSString *username;
#property (nonatomic,strong)NSString *facebookID;
#property (nonatomic,strong)NSString *userPSW;
#property (nonatomic,strong)NSString *userID;
#property (nonatomic,strong)NSMutableArray *friendsList;
#property (nonatomic,strong)NSMutableArray *groups;
#property (nonatomic,strong)NSData *audioMessage;
#property (nonatomic,strong)NSMutableArray *mimosToDownload;
#property (nonatomic,strong)NSMutableArray *mimosDownloaded;
#property (nonatomic,strong)friend *friendToSend; //Here is where a I get the error of unknown type name
#end
this is the friend.h
#import <Foundation/Foundation.h>
#import "currentUser.h"
#import "Imager.h"
#interface friend : NSObject<NSCoding>
#property (nonatomic,strong)NSString *username;
#property (nonatomic,strong)NSString *userID;
#property (nonatomic,strong)UIImage *userImg;
#property(nonatomic,strong)NSMutableData *buffer;
#property(nonatomic)BOOL flagDownloaded;
-(UIImage*)downloadImageBlocked;
-(id)init;
-(UIImage*)getFriendImg;
-(UIImage*)userImg;
-(NSString*)getUserID;
-(NSString*)getUserName;
- (void)encodeWithCoder:(NSCoder *)encoder;
-(bool)isNil;
#end
fix the stuff that you know is wrong first...
change
#interface currentUser : NSObject<NSCoding>
{
BOOL fromfacebook;
#private
NSMutableArray *upLoadStack;
}
to
#interface User : NSObject<NSCoding>
{
BOOL fromfacebook;
#private
NSMutableArray *upLoadStack;
}
you don't need to know if the user is current or not for the user to have properties of a user, think of them as actually representing objects.
change:
#interface friend : NSObject<NSCoding>
to
#interface Friend : NSObject<NSCoding>
you know it is wrong, fix it now before you have to fix it in 1000 places instead of 100 places.
Convention is very important in Objective-C.
also don't import everything into your header if you don't need to...
#class Friend; //forward class declaration
#interface currentUser : NSObject<NSCoding>
...
#property (nonatomic,strong)Friend *friendToSend; //Here is where a I get the error of unknown type name
and as for your ivar's in currentUser you don't need those in the interface (they can go in a block after the #implimentation line), unless you need them for backwards compatibility...

Why do default Storyboard apps have a second interface declaration

Sorry if this is stupid... but it confuses me?...
I'm trying a new storyboard app with Xcode and just asked myself why there is a second declaration of the #interface in my implementation file?
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
}
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
....
#end
See Apple's documentation: https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html
It's a class extension, subtly different from a category, since it has no name inside the parentheses. You use it for declaring properties and methods that are intended to be kept private (out of the header), and redeclaring publicly read-only properties and methods as privately read-write. This allows for cleaner encapsulation.
By request, a friendly example:
JYDuckPondManager.h
#interface JYDuckPondManager : NSObject
#property (nonatomic, assign, readonly) NSUInteger duckCount;
#property (nonatomic, assign, readonly) CGFloat waterLevel;
- (JYDuckReaction *)feedDucks:(JYDuckFood *)food;
- (JYDuckReaction *)harassDucks:(JYDuckTaunt *)taunt;
#end
JYDuckPondManager.m (extension, imaginary implementation omitted)
#interface JYDuckPondManager ()
//// Redefined for internal modification
#property (nonatomic, assign, readwrite) NSUInteger duckCount;
#property (nonatomic, assign, readwrite) CGFloat waterLevel;
//// Internally exclusive properties
#property (nonatomic, strong) NSSet *duckPersonalitySet;
#property (nonatomic, assign) CGFloat flockAnxietyLevel;
//// Private messages
- (void)recalculatePondState;
#end
Other objects should be able to interact with the pond, but they're not supposed to know certain things going on in the pond or redefine the pond's statistics. Keeping nuts-and-bolts stuff in the .m extension ensures that the .h is concise and appropriately limited.
The second #interface block in the .m file is an extension. You could add declarations for methods and instance variables you want to use internally within your class.
The second interface #interface ViewController () is a class extension which is like an anonymous category. A class extension is declared like a category only without a name. Declarations found in these extensions directly extend the declarations found in the class’s primary #interface and can sometimes (in some situations) override declarations found in the primary interface.

Resources