Forward Declaration - objective-c

I was building an app when I ran into some errors. After doing some research, I found that the reason is because I am working with 2 files, that each #import each other. I read that the cure to this is to use Forward Declaration, but I couldn't find a good example of how this is done.
Here is what I have.
RootViewController.h
#import <UIKit/UIKit.h>
#import "FirstDetailViewController.h"
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
#interface RootViewController : UITableViewController <UISplitViewControllerDelegate, FirstDetailViewControllerDelegate>{
UISplitViewController *splitViewController;
UIPopoverController *popoverController;
UIBarButtonItem *rootPopoverButtonItem;
NSMutableArray *logMessages;
}
#property (nonatomic, assign) IBOutlet UISplitViewController *splitViewController;
#property (nonatomic, retain) UIPopoverController *popoverController;
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
#end
FirstViewDetailController.h
#import <UIKit/UIKit.h>
#import "RootViewController.h
//test2
#protocol FirstDetailViewControllerDelegate <NSObject>
- (void)addItemViewController:(FirstDetailViewController *)controller didFinishEnteringItem:(NSString *)item;
#end
//end test2
#interface FirstDetailViewController : UIViewController <SubstitutableDetailViewController> {
//for the output
IBOutlet UITextView *outputView;
UIToolbar *navigationBar;
}
#property (nonatomic, retain) IBOutlet UIToolbar *navigationBar;
//test
#property(nonatomic, retain) NSString *message;
//end test
#property (nonatomic, retain) id <FirstDetailViewControllerDelegate> delegate;
#end
I know that I need to replace #import with #class, but do I do it for both occurrences? Also, I a already #import "FirstDetailViewController.h" in the RootViewController.m file, so do I switch it there as well ?
I am a little confused so any help would be appreciated !

Forward declaration would be the solution if it were just pointers you needed, but you are implementing the other header's protocol in each class.
My suggestion would be to declare your protocols in some other header file, such as MyProtocols.h and include that in both of your .h files instead of the controllers' headers.
On a side note, having a strong, or retained reference to one's delegate isn't really standard practice, as this can easily cause a retain cycle which leads to leaked memory

Replace
#import "FirstDetailViewController.h"
with
#class FirstDetailViewController;
Replace
#import "RootViewController.h" with
#class RootViewController;
in RootViewController.m, make sure you have
#import "RootViewController.h"
#import "FirstDetailViewController.h"
in FirstDetailViewController.h make sure you have
#import "FirstDetailViewController.h"
#import "RootViewController.h"
Edit: Oops missed the protocol references... Dan F's answer is correct

Related

cocoa-Why there is an IBOutlet and a property that are of the same name?

I'm new to objective-c. When I'm reading some source code written by others, I encountered a problem.
I found that there is
IBOutlet NSPopover *popover;
as well as
#property NSPopover *popover;
PopoverViewController.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "TimerPopoverViewController.h"
#class TimerLogic;
#class TimerInfo;
#interface TimerPopoverDelegate : NSObject <NSPopoverDelegate> {
#private
IBOutlet NSPopover *popover;
IBOutlet NSWindow *detachWindow;
IBOutlet TimerPopoverViewController *viewController;
}
#property NSPopover *popover;
- (void)showPopover:(id)sender timerInfo:(TimerInfo *)timerInfo;
#end
I think they are different variables. However, I can't figure out what do they do?
As far as I'm concerned, the IBOutlet is to show a popover.
But what does the #property does?
This is either very old code or written in a very old (and now discouraged) style. The IBOutlet here is declaring an instance variable (ivar). The #property is declaring a property that is backed by the instance variable. In modern ObjC you should implement it this way:
PopoverViewController.h
#import <Cocoa/Cocoa.h>
#class TimerInfo;
// Things declared here are public
#interface TimerPopoverDelegate : NSObject <NSPopoverDelegate>
// You could leave this here if it is required by other parts of the program,
// but other parts of the program really shouldn't require it. See below.
// #property (nonatomic, readonly, weak) NSPopover *popover;
- (void)showPopover:(id)sender timerInfo:(TimerInfo *)timerInfo;
#end
PopoverViewController.m
// Generally avoid importing local headers into the .h unless you have to.
#import "TimerPopoverViewController.h"
// Things declared here are private. This is much better than the old #private.
#interface TimerPopoverDelegate ()
#property (nonatomic, readwrite, weak) IBOutlet NSPopover *popover;
#property (nonatomic, readwrite, weak) IBOutlet NSWindow *detachWindow;
#property (nonatomic, readwrite, weak) IBOutlet TimerPopoverViewController *viewController;
#end
(Currently popover is public, but you should avoid exposing an IBOutlet that way. Outside objects should not directly touch a view controller's outlets.)

Xcode displays error when building Mac app for release

I'm writing an application for OS X using core data. It's no problem to build and run it for debugging but when I switch to release or try to archive it, it throws the error
'/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreData.framework/Headers/NSFetchRequestExpression.h:15:39: Attempting to use the forward class 'NSExpression' as superclass of 'NSFetchRequestExpression'
When I delete all fetch request from the code, it works fine.
Does anybody know what problem this could be? Thank you.
Here are the header:
#import <Cocoa/Cocoa.h>
#import <CoreData/CoreData.h>
#import "EFMainController.h"
#interface EF_AppDelegate : NSObject
{
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
NSWindow *window;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
EFMainController *mainController;
NSTabView *tabView;
IBOutlet NSImageView *dockTileView;
}
#property (nonatomic, retain) IBOutlet NSWindow *window;
#property (nonatomic, retain) IBOutlet EFMainController *mainController;
#property (assign) IBOutlet NSTabView *tabView;
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
- (NSManagedObjectModel *)managedObjectModel;
- (NSManagedObjectContext *)managedObjectContext;
- (IBAction)saveAction:sender;
#end
and
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface EFMainController : NSObject {
/* some variables */
}
/* some properties and actions */
#end
The stuff where I put the comments has nothing to do with core data
I have a program where I experience the same Problem and so far I could not really solve it but I was able to somewhat build it for release. So I guess this is not a real/full answer but for me it worked to use Product > Build For > Archiving.

Setting up the App Delegate to Manage Data

I'm working on an app with a Split View controller and would like to store the main data class in the App Delegate so I can access it from multiple views (MasterView, DetailView, and several PopUps).
I'm a bit of a noob and can't figure out why Im getting the error:
AppDelegate.m:31:26: Property 'dataController' not found on object of type 'MasterViewController'
Below is the relevant code - any help is much appreciated. Thanks.
AppDelegate.h
#import <UIKit/UIKit.h>
#class EventClassDataController;
#class MasterViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import <UIKit/UIKit.h>
#class EventClassDataController;
#class MasterViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
MasterViewController.h
#import <UIKit/UIKit.h>
#class DetailViewController;
#class EventClassDataController;
#interface MasterViewController : UITableViewController
#property (strong, nonatomic) EventClassDataController *dataController;
#property (strong, nonatomic) DetailViewController *detailViewController;
#end
MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#import "EventClassDataController.h"
#import "EventClass.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
#synthesize detailViewController, dataController;
- (void)awakeFromNib
{
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
[super awakeFromNib];
// Initialize event data
self.dataController = [[EventClassDataController alloc] init];
}
EventClassDataController.h
#import <Foundation/Foundation.h>
#class EventClass;
#interface EventClassDataController : NSObject
#property (nonatomic, copy) NSMutableArray *masterEventList;
-(NSUInteger)countOfList;
-(EventClass *)objectInListAtIndex:(NSUInteger)theIndex;
-(void)addNewEvent:(EventClass *)event;
-(void)removeEvent:(EventClass *)event;
#end
You need to add
#import "MasterViewController.h"
to AppDelegate.m.
Explantation:
From your error message I can tell that you're trying to access a property of MasterViewController on line 26 of your AppDelegate. However, in your AppDelegate class you only have a forward declaration ("#class MasterViewController") and you don't include the actual header file for MasterViewController. What this means is that AppDelegate knows there exists a class named MasterViewController somewhere in your project... but that's all it knows. AppDelegate doesn't know anything about the contents of MasterViewController, i.e. properties or methods MasterViewController declares.
The reason to use #class in a header file is so that you can have properties in an #interface such as
#property (nonatomic, strong) MasterViewController * appDelegatesReferenceToMasterViewController;
without having to import MasterViewController.h in AppDelegate.h. This way, other files in your project can import AppDelegate.h without also inadvertently importing MasterViewController.h.
Translation:
You writing the code:
#class MasterViewController;
is like saying to the compiler:
Yo... compiler. I'm going to be talking about something called MasterViewController in this header file and you don't know what a MasterViewController is... but don't trip out bro. It's all good.
But then, later in the .m file after you write the code:
... masterViewController.dataController ...
the compiler responds:
Whoa, whoa, whoa. I was cool with you just having a variable with the type MasterViewController in the header file because you told me it was all good and not to worry. But now here you are trying to use some aspect of MasterViewController that I know nothing about. How am I supposed to know if this is legal or not? Not cool bro.

Objective C: "Property implementation must have its declaration in interface"

I have the following code:
//RootViewController.h:
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController{
IBOutlet UITextField *login_uname;
IBOutlet UITextField *login_pword;
IBOutlet UIActivityIndicatorView *login_thinger;
IBOutlet UIImageView *logo;
IBOutlet UISwitch *login_remember;
IBOutlet UIScrollView *scrollView;
}
-(IBAction) login_submitClick:(id)sender;
-(IBAction) doneEditing:(id)sender;
-(IBAction) clearPword:(id)sender;
-(void) showSignUp:(id)sender;
-(void)doLogout:(id)sender;
//for file handling:
-(NSString *)documentsPath;
-(NSString *)readFromFile:(NSString *)filePath;
-(void) writeToFile:(NSString *)text withFileName:(NSString *) filePath;
#end
//RootViewController.m
#import "RootViewController.h"
//#import "Main.h"
//#import "SignUp.h"
#import "ASIHTTPRequest.h"
#import "ASIFormDataRequest.h"
#import "CommonCrypto/CommonHMAC.h"
#import "Details.h"
//#import "signUpSMS.h"
#import "JSON.h"
#implementation PrestoCab3ViewController
#synthesize login_uname; //this line throws the error in the title
...
I'm using XCode 4.1 and was wondering if someone could please help me get to the bottom of this error. I'm very new to XCode.
Many thanks in advance,
You need to declare the property with #property in your interface.
#property( nonatomic, retain ) IBOutlet UITextField * login_uname;
Here, non-atomic is used because it's an IBOutlet.
Also note the property has the retain modifier, meaning you are responsible to release the object when you don't need it anymore.

Method definition not found

What am I doing wrong? This is the .h file:
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#class ReaderViewController;
#interface ReaderAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ReaderViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ReaderViewController *viewController;
- (void)checkForDatabase;
//- (void)SQLiteConnection: (NSString *)defaultDBPath;
#end
The error is shown here:
You are calling the [self checkForDatabase] method which doesn't appear to exist in the .m file.
The Incomplete Implementation warning is because you have declared the checkForDatabase method in your interface
The Method Definition error is because you are attempting to call the missing method in the application:didFinishLaunchingWithOptions: method.
You have failed to implement checkForDatabase in ReaderAppDelegate.m (or in any other file you're linking into the project). You said you would in the header, and then you didn't.