How do I resolve this circular dependency? - iphone

I'm new to iOS development and am running into an issue with my header files. I'm running into a circular dependency issue with my header files. My application delegate class contains a pointer to my view controller, since I have to set one of the view controller's properties in my didFinishLaunchingWithOptions method...
//appDelegate.h //DISCLAIMER: THIS IS UNTESTED CODE AND WRITTEN ON THE FLY TO ILLUSTRATE MY POINT
#import <UIKit/UIKit.h>
#import "MyViewController.h"
#interface appDelegate
NSManagedObjectContext *managedObjectContext;
MyViewController *viewController;
BOOL myFlag;
#end
//appDelegate.m
#implementation appDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
viewController.managedObjectContext = self.managedObjectContext;
.
.
.
}
#end
And in my view controller, I reference the "myFlag" property, that's in my app delegate...
//MyViewController.h
#import "appDelegate.h" //<---circular dependency, causing "Expected specifier-qualifier-list before MyViewController" errors in my appDelegate header file
#interface MyViewController: UIViewController
{
NSManagedObjectContext *managedObjectContext;
}
#end
//MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
((appDelegate*)[[UIApplication sharedApplication] delegate]).myFlag = NO;
}
#end
But in order to access the "myFlag" property in my app delegate, I need to import the app delegate's header file. This is what's causing the circular dependency. Not sure how to resolve this, has anyone run into this?
Thanks in advance for your help!

Don't #import "MyViewController.h" in appDelegate.h. Instead, forward-declare the class.
#class MyViewController;
#interface appDelegate
NSManagedObjectContext *managedObjectContext;
MyViewController *viewController;
BOOL myFlag;
#end
Also, you don't need to #import "appDelegate.h" in MyViewController.h if all you need is to reference the myFlag property in the implementation. Instead, import it in the MyViewController.m file.

#class is the syntactic approach you're looking for.
Many coders look to avoid this circularity (which couples your classes in two directions, meaning your view controller can only be used in circumstances where the app delegate has that BOOL). There are a few ways you can do this:
Move the state variable to a singleton
Have the view controller fetch the value through an interface that the delegate implements
Key-Value Observing (which your app delegate would configure on your view controller)
For small projects this kind of dependency is probably not really a problem, but as project size grows and the desirability of code reuse grows, clean functional separation becomes more and more valuable.

Did not read everything, but you can do forward declarations with #class. Usually how I solve circular dependencies.

Related

It's possible create a custom delegate in AppDelegate?

i want know if it's possible create a custom delegate in the AppDelegate class, like in this way for instance:
#protocol AppDelegateDelegate <NSObject>
- (void)finishSync:(BOOL)success;
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate> {
#property (nonatomic, weak) id <AppDelegateDelegate> delegate;
#end
it's possible create something like this? to notify the classes that are registered for this delegate?
EDIT
How i can use the Delegate? for example if i do this:
#import "AppDelegate.h"
#interface MasterViewController : UIViewController <AppDelegateDelegate>
#end
.m
#implementation MasterViewController
...
- (void)viewDidLoad {
AppDelegate *appController = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appController.customDelegate = self;
}
in i stay only in that view works, but for example if i switch in SecondViewController that have the same code to implement the delegate, the delegate don't works anymore neither in the MasterViewController...what i wrong?
Yes, That is fine. You can create delegates anywhere you want and use it anywhere by importing that class. There are no restrictions.

Defining delegate function in separate file (instead of in ViewController)

I have a ViewController, and a UIView.
The UIView has a delegate, and the delegate function is set in the ViewController.
All I want to do, is have the delegate function defined in a separate file. So the UIView.m #imports the separate file, instead of all the ViewControllers which use the UIView.
I believe this is a standard procedure, but keep falling over myself trying to get it to work. :| Would really appreciate some help. Thanks.
myViewController.h
#import <UIKit/UIKit.h>
#import "myUIView.h"
#protocol ModalViewDelegate
-(void)didReceiveMessage:(NSString *)message;
#end
#interface myViewController : UIViewController <ModalViewDelegate>
#property (nonatomic, strong) myUIView *myUIViewItem;
#end
myViewController.m
#import "myViewController.h"
#import "myUIView.h"
#interface myViewController ()
#end
#implementation myViewController
#synthesize myUIViewItem;
- (void)didReceiveMessage:(NSString *)message { //<<< THIS IS WHAT
NSLog(#"Message from button: %#", message); //<<< NEEDS MOVING
}
- (void)viewDidLoad
{
…
myUIViewItem.delegate = self;
…
myUIView.h
#import <UIKit/UIKit.h>
#protocol ModalViewDelegate;
#interface myUIView : UIView {
id<ModalViewDelegate> delegate;
}
#property (nonatomic, strong) id<ModalViewDelegate> delegate;
myUIView.m
#import "myUIView.h"
#import "myViewController.h"
#implementation myUIView
#synthesize delegate;
...
[delegate didReceiveMessage:#"Data from UIView!"];
well, there is one method actually,
Just take one .h file and lets say connectionDelegate.h and declare your protocol init
In connectionDelegate.h:
#import <UIKit/UIKit.h>
#protocol ConnectionDelegate
-(void)getResult:(NSString*)_result;
#end
Then in your view controller:
#import "ConnectionDelegate.h"
#interface myViewController : UIViewController <ConnectionDelegate>
{
id delegate;
}
then in .m file, by just call the method
[delegate getResult:_result];
Edit regarding the warnings:
You need to declare the method in view controller, you need to do like this.
[self getResult:urlDataString];
-(void)getResult:(NSString*)_result{
[delegate getResult:_result];
}
Based on your comment:
I want to have the function 'didReceiveMessage' defined in a SEPARATE
file. So that I don't have to repeat it in every ViewController that
uses the UIView and delegate. e.g. ModalViewDelegate_Action.h and
ModalViewDelegate_Action.m
The way I was given was to use a subclass, and that's been working great for me. In my iOS projects I have a class called BaseViewController, which is a subclass of UIViewController. I put lots of code in it related to HUD management, NSOperations management, etc. Then virtually all my view controllers are subclasses of it.

method not found

I'm working on an application with three tabs plus a small view in which I created a sort of TopBar that contains some info and some buttons.
In the main application delegate I define:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
//here we add the topBar:
topBarViewController = [TopBarViewController instance];
topBarViewController.appDelegate = self;
[window addSubview:topBarViewController.view];
...
}
- (void)showReplyView
{
self.tabBarController.selectedViewController =
[self.tabBarController.viewControllers objectAtIndex:2];
}
as you can see I set the .appDelegate in the topBar to make some call back in the code of the topBar (ie: when I want to change the tab currently visualized)
Now in my TopBarViewController.h I have:
#interface TopBarViewController : UIViewController {
MyAppDelegate *appDelegate;
...
}
#property (nonatomic,retain) MyAppDelegate *appDelegate;
-(void)testMethod;
and in the .m file:
#implementation TopBarViewController
#synthesize appDelegate;
...
-(void)testMethod{
[appDelegate showReplyView];
}
...
When I build the project the compiler tell me that the showReplyView method doesn't exist.
I tried everything and I'm sure that there are no typo errors...
Is it possible that I can't reference to the delegate?
Thanks to anyone would help me...
I found the problem:
in the TopBarViewController.h I was declaring #class MyAppDelegate; since I couldn't make an import (avoid the loop).
So the compiler was not able to find out which methods were declared.
To solve it I import the #import MyAppDelegate.h directly in the TopBarViewController.m!
Thanks anyway for the help!
Have you defined showReplyView in the #interface for MyAppDelegate?

Consequence of importing appDelegate in a class and the same class in appDelegate

I want to know the consequence of importing appDelegate in a class and the same class in appDelegate. Because, I'm doing this in my application successfully, but it's recommended that it should not be done. I couldn't find the answer despite a lot of searching.
Thanks in advance.
You can do it, but be careful with how you import headers. This is the recommended way:
AppDelegate.h:
// Import headers here
#class MyViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
MyViewController *viewController;
}
- (void)someMethod;
#end
AppDelegate.m:
#import "AppDelegate.h"
#import "MyViewController.h"
#implementation AppDelegate
//Your code here
#end
MyViewController.h:
// Import headers here
#class AppDelegate;
#interface MyViewController : UIViewController {
AppDelegate *appDelegate;
}
#end
MyViewController.m:
#import "MyViewController.h"
#import "AppDelegate.h"
#implementation MyViewController
// Your code here
#end
As you can see, you want to use #class to declare the classes in your headers, and then import the header in your .m files. This ensures that you’re not importing things that you don’t need; if you imported the view controller header in your app delegate’s header, it would be imported into anything that imported your app delegate’s header. By leaving all the imports to the .m files, you prevent that situation.

Warning when communicating context from controller to NSView with custom methods

Coding against UIKit for iPhone.
Setup, with relevant detail:
SomeView.h:
#import <UIKit/UIKit.h>
#interface SomeView : UIView {
SomeObject *myObject;
}
#property (assign) SomeObject *myObject;
-(void) doSomething;
#end
SomeView.m:
#import "SomeView.h"
#implementation SomeView
#synthesize myObject;
- (void)doSomething {
NSLog(#"doing something");
}
- (void) drawRect:(CGRect)rect {
// drawing is based on myObject
}
#end
Controller.h:
#import <UIKit/UIKit.h>
#import "SomeView.h"
#interface Controller : NSObject {
IBOutlet UIView *someView;
}
#end
Controller.m:
#import "Controller.h"
#implementation Controller
-(void)awakeFromNib {
[someView doSomething];
[someView setSomeObject:someObject];
}
#end
I am instantiating the controller object in Interface Builder, and SomeView is the class of one of my custom UIViews in my app's main window.
Now, the questions:
1) when I run the above, I get warnings for both lines: "Warning: 'UIView may not respond to 'doSomething'" and similar warning for setSomeObject. Why? (The code actually seems to work, but I don't like seeing the warnings.)
2) is this the right way of doing things? What I am really after, is making SomeView aware of someObject, so that when drawRect for SomeView is called, it can change its behavior based on current state of someObject. I don't need to have the object directly in SomeView; I could have it in the controller, but the view still needs some information from it that may change at runtime.
You declared someView as an instance of UIView, but doSomething is a method of SomeView. So it is correct — the class you told the compiler that the variable points to does not respond to that message. If you don't want warnings, you'll have to make it a SomeView * instead of a UIView *.
Otherwise, your general architecture looks OK to me.