Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode classes can't "see" one another

I was working on an Xcode project and everything was going great, until two of my classes stopped recognizing each other. Here is an excerpt:

#import "JBXViewController.h"
@interface ViewController2 : UIViewController {
    JBXViewController *jbx;
}

For some reason I get the error "Unknown type name 'JBXViewController'; did you mean 'UIViewController'?" I don't understand how this is possible, since I'm importing the other class just a few lines above. Any insights would be much appreciated!

like image 470
serverpunk Avatar asked Dec 28 '11 06:12

serverpunk


2 Answers

When you say they "can't see each other", I assume you mean you are also importing ViewController2.h in your JBXViewController.h. So you have one header importing another header, which imports the first header, which imports the second, which imports the first again...

Instead, use a forward reference to JBXViewController:

@class JBXViewController;

@interface ViewController2 : UIViewController {
    JBXViewController *jbx;
}

And then #import "JBXViewController.h" in your implementation instead (in your ViewController2.m)

like image 154
Firoze Lafeer Avatar answered Nov 03 '22 04:11

Firoze Lafeer


Firoze Lafeer's answer is correct, but this problem is probably a symptom of poor design in your code.

I assume that, in your app, JBXViewController is a parent view controller, and it sometimes shows a ViewController2 for some specific function. (For example, JBXViewController shows a list of records, while ViewController2 edits one of the records.) In a situation like this, ViewController2 should not know the details of JBXViewController. Instead JBXViewController should give ViewController2 the data it needs via ViewController2's properties, and if ViewController2 has to call methods on JBXViewController, they should be part of a delegate protocol.

For example, suppose JBXViewController currently has the following property, and ViewController2 accesses it:

@property (strong) JBXObject * currentObject;

You should instead have a currentObject property on ViewController2, and JBXViewController should set it before showing the view controller:

self.myViewController2.currentObject = self.currentObject;
[self.navigationController pushViewController:self.myViewController2 animated:YES];

This works for one-way communication—JBXViewController can give ViewController2 data. If data needs to flow back up to JBXViewController (other than by changing currentObject's properties), you should set up a delegate for ViewController2. For example:

@protocol ViewController2Delegate;    // forward declaration
@interface ViewController2 : UIViewController
@property (weak) id <ViewController2Delegate> delegate;
...
@end

@protocol ViewController2Delegate <NSObject>
- (void)viewController2ShouldSave:(ViewController2*)viewController2;
- (BOOL)viewController2:(ViewController2*)viewController2 shouldAddSomoflange:(JBXSomoflange*)aSomoflange;
@end

Then have JBXViewController conform to the protocol:

@interface JBXViewController : UIViewController <ViewController2Delegate>

Set the delegate, either in Interface Builder or in code like so:

self.myViewController2.delegate = self;
self.myViewController2.currentObject = self.currentObject;
[self.navigationController pushViewController:self.myViewController2 animated:YES];

And implement all the methods listed in ViewController2Delegate.

Together, these changes mean three things:

  1. ViewController2 does not need specific knowledge of how JBXViewController works. This means you no longer have to import JBXViewController.h in ViewController2.h, which solves your immediate problem.

  2. JBXViewController is now more flexible. As long as it sets the appropriate properties in ViewController2 and implements any necessary delegate methods, you can change anything you want in JBXViewController and ViewController2 will never know or care about it.

  3. ViewController2 is now more flexible too. You can use it from other parts of the app, or move it to another app. You can insert a screen between JBXViewController and ViewController2.

These changes aren't necessary to get the app running on your device and functioning the way you intend. But you'll have an easier time down the road if you start adopting these sorts of designs.

like image 31
Becca Royal-Gordon Avatar answered Nov 03 '22 05:11

Becca Royal-Gordon