0

I have a custom UIView class which needs to know about its parent (another different custom UIView class).

  1. The parent class has to import the header of the child class, so it can add subviews of that class.
  2. The child class has to import the header of the parent class, so it can access its methods and properties. It has to do the import in its .h file rather than its .m, because I need to make the child's parent an instance variable.
  3. If I do this, I get circular import issues.

If anyone can make any sense of this, can you help to resolve this? Thanks.

James White
  • 774
  • 1
  • 6
  • 18
  • 2
    First that comes into mind is why the parent has to know about the children. That aside, you can make a forward declaration of the child in the parent header (not an import). refer to http://stackoverflow.com/questions/5191487/objective-c-forward-class-declaration – dmaij Jan 10 '13 at 01:29
  • 1
    James, it might help if you could put "make babies" and "understand what manner of beast" into more technical language, perhaps with code samples. @dmaij You should make your comment into an answer. – Jesse Rusak Jan 10 '13 at 01:33
  • Why the parent has to know about it's children? How could it add a subview of a particular custom class, without importing the header of that class? But thanks for the link. – James White Jan 10 '13 at 01:33

3 Answers3

2

What you want is commonly known as a forward declaration.

refer to Objective-C: Forward Class Declaration for more information

Community
  • 1
  • 1
dmaij
  • 1,017
  • 7
  • 15
0

There are many ways to solve this, for example by just declaring the reference to the other class as an id, and to send forward messages to it (in Objective-C you don't even need to cast them, the compiler wouldn't complain about that).

For example:

@property(nonatomic,weak) id child;

But you may review your design in a way that you use a root controller that handles both the classes. This way A doesn't directly speak to B and B doesn't directly speak to A. Instead if A wants to speak with B, speaks with C and C speaks with B, and viceversa.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
  • Sorry, I'm not sure exactly what that means. Is that the same as using @class, as described in dmaij's link, or a different approach? – James White Jan 10 '13 at 01:38
  • No, you just declare your property to be an id, I added an example. – Ramy Al Zuhouri Jan 10 '13 at 01:39
  • It would be better to use `@class` so you can declare the property with an appropriate type. Using `id` is far from ideal. The compiler can no longer help you ensure the right methods are being called and it is far from self documenting. The answer by dmaij is a much better solution than this one - sorry Ramy. – rmaddy Jan 10 '13 at 01:53
  • However if you use @class in the .h file, then in the .m file you still have to use the import directive to use these methods. – Ramy Al Zuhouri Jan 10 '13 at 02:00
  • @Ramy, I'd trust rMaddy on that one. Nobody ever imports .m files, so there's zero risk of circular imports. – CodaFi Jan 10 '13 at 02:24
0

While you could use a forward declaration (@class ParentClass) and a weak reference to the parent (@property (nonatomic, weak) ParentClass *parent) in the child's header file, this is generally not a good programming practice.

Reasons why this is generally not a good idea:

1) As the project gets bigger, you're likely going to violate DRY ("don't repeat yourself") as the child necessitates a parent of a certain class... what if another parent later needs to create the same child object? You'd have to create a new class that declares another forward class of the new parent and has a weak property to it.

2) This is also likely going to lead to spaghetti code... what if you want to add a new feature to the parent that affects a method the child is using? Do you create a new yet similar method that's slightly different (see point 1 about violating DRY)? Do you create an input to the original method (you'd also have to make sure that the child now knows about this change and passes the appropriate input).

Instead, the Delegation design pattern works better here. Apple also frequently uses this throughout their libraries. In example, UITableView declares a delegate and a datasource so that it can delegate actions (clicks on cells) and data input (creation of custom cells) to other owning classes, without the UITableView object having to know about the implementation of said parent class.

For more information on the Delegation pattern in general, see Wikipedia on it here:

http://en.wikipedia.org/wiki/Delegation_pattern

For a tutorial on creating your own protocols (how delegation is implemented in iOS), see this tutorial here:

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-custom-delegates/

For high quality tutorials and introductions on iOS in general, including delegation and other necessary iOS concepts, see Ray Wenderlich's site also here:

http://www.raywenderlich.com/

Good luck!

JRG-Developer
  • 12,454
  • 8
  • 55
  • 81