I have a location class in my project which calls methods in different several view controllers. I have defined the class in each view controller as self which works fine but when I push to and from other view controllers it starts behaving irrationally and calls the method in the wrong controller causing all sorts of problems
My location class is setup correctly and I believe I have called them correctly but I am obviously missing something like deallocating the delegate once I am done with it?
This is what is in each of my view controllers
.h
#import "AHLocationClass.h"
AHLocationClass *location;
#interface AHSelectionController : UIViewController <AHLocationDelegate> {
.m
location = [[AHLocationClass alloc] init];
location.delegate = self;
Note, I know using notification will fix this but in my project using this method will quickly make things messy
It turns out that declaring globally was my issue, declaring it as a property fixed this inconsistency.
#property (nonatomic, strong) AHLocationClass *location;
Related
This behavior is very odd. Every time I create a new project in Xcode 5.0.2 I cannot get it to work fully. Once the Single View Application template (or another) is created - everything seems OK: I have my delegate, storyboards and ViewController. They all run successfully and I can even see newly added UIView's in my Simulator.
Her is my generic code for ViewController:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
UIView *container;
}
#property (nonatomic,retain) IBOutlet UIView *container;
#end
#import "ViewController.h"
#interface ViewController (){}
#end
#implementation ViewController
#synthesize container;
- (void)viewDidLoad{
[super viewDidLoad];
NSLog(#"App loaded");
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
#end
But once I add properties to this controller class and synthesize them, the screen turns black during app running and no views or whatever was added before is ever seen anymore. Just a blank black color screen.
Where is the problem? Please note:
I checked Info*.plist and it points to Storyboard correctly
In delegate my didFinishLaunchingWithOptions returns YES
ViewController has a Initial View Controller checked and is the only one in the storyboard
viewDidLoad prints NSLog message successfully even though nothing is shown
What to check?
Here is a link to the project
A view controller is just that, a controller. The UIViewController's view property is what is visible on the screen (assuming you added it to the screen at some point, storyboard, programatic, xib, etc...)
Check the UIViewcontroller.view.superview. You should be able to get close to what you want.
The view controller properties thing is a complete red herring.
You're using a storyboard for your app, which has all of the relevant details in it. Then, in your app delegate, you've added a load of code to load in a new instance of the view controller and set it as your app's root view controller.
You don't need to do this if you have a storyboard. Just return YES from applicationDidFinishLaunching.. (which was originally the case, since you included the git history in the download!). The initial view controller from your storyboard will already be loaded up. What you've done is to basically ignore the storyboard.
I'm trying to get MMDrawerController to work, and I'm having trouble.
Here's is how much app is structured in my storyboard:
Here's how I'm attempting to initialize it from within my root view controller:
//LCViewController.m
#import "LCViewController.h"
#import "MMDrawerController.h"
#interface LCViewController ()
#property (nonatomic,strong) MMDrawerController * drawerController;
#end
#implementation LCViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.drawerController = [[MMDrawerController alloc]
initWithCenterViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"centerNav"]
leftDrawerViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"menu"]
rightDrawerViewController:nil];
}
...
#end
When I build my app, all I see is my root view controller. Is there something else I'm supposed to do to implement the drawer functionality?
I created a demo project to show how I'm trying to set up my app. You can download the Xcode workspace here. Thanks in advance for your help!
I'm using Xcode 5 and iOS 7
EDIT: Sorry I initially misunderstood your app structure. The MMDrawerController should be the root view controller of your application. You should move this code from viewDidLoad to application:didFinishLaunchingWithOptions:. Add an MMDrawerController property to your app delegate, init the drawer controller with your appropriate views, and set the drawer controller to the rootViewController on your UIWindow. Do this along with setting the gesture modes as I described below and the drawer should work.
To get the basic open/closing gestures, set this properties on your drawer controller:
self.drawerController.openDrawerGestureModeMask = MMOpenDrawerGestureModeAll;
self.drawerController.closeDrawerGestureModeMask = MMCloseDrawerGestureModeAll;
These properties default to MMOpenDrawerGestureModeNone which is why you couldn't make anything slide. You can have a look at the MMOpenDrawerGestureMode and MMCloseDrawerGestureMode bitmasks to get finer grained settings if you desire.
You can also create UI controls that toggle the drawer by calling toggleDrawerSide:
animated:
completion:.
I have a relatively simple application. I have a UINavigationController and always have my mainViewController pushed on it. Occasionally I'll push on a settings and sub-settings controller. In my sub-settings controller, the user can make modifications to ivars in my mainViewController. Right now I have these ivars declared as properties and am setting them directly. I am using self.navigationController.viewControllers[0] to get a reference to the main controller then setting the properties. Is it better to use NSNotificationCenter?
It is not a very good design to have your settings controllers have any knowledge of your primary view controller. What happens when you add more functionality to your app in the future and more screens in the app need to deal with changes in any settings?
It is a far better design to separate the behavior. Your settings view controllers should update a "settings model" of some sort. The class representing this model should then be able to broadcast any changes. Using NSNotificationCenter for this is a good approach.
Now any class that might care about changes in settings can register for the appropriate notifications and act accordingly when there is a change.
This way you can have multiple view controllers or other classes that respond to settings changes and nothing in the settings code needs to care about any specific view controllers or how many there are.
What you are doing is fine since you can easily get a references to your main view controller from your settings view controllers. It's really just a matter of preference.
The real purpose of NSNotificationCenter is when multiple objects need to be notified of an event or where it's difficult to get a reference to the object you want to modify. NSNotificationCenter can also make your code cleaner and easier to modify.
For instance, if you change the design of your app in the future such as moving the settings view controllers to tabs rather than pushing them onto a navigation controller you might find it more difficult to modify your main view controller directly from them.
It would be more appropriate to use NSNotificationCenter when you have disparate components in your app that would logically have no understanding of each other's API. However, where you are displaying a view for a sub-settings controller, it would be easy to have a settings object that you could just pass from the mainViewController to the subSettingsViewController. In your sub-settings view controller, in the -viewWillDisappear: memthod, ensure that all of the values have been saved to your settings object. Finally, in your main view controller's -viewWillAppear: method, you would just update the UI of the main view with the values in your settings object.
Here's some code to illustrate this:
MainViewController.m
#interface MainViewController ()
#property (nonatomic, strong) MySettings *settings;
#property (nonatomic, strong) SubSettingsViewController *subSettingsViewController;
#end
#implementation MainViewController
- (IBAction) showSubSettings: (id) sender {
[self.subSettingsViewController setSettings: self.settings];
// Present 'subSettingsViewController'
}
- (void) viewWillAppear: (BOOL) animated {
[super viewWillAppear: animated];
// Set values from settings object for various text fields, UI controls, etc.
}
SubSettingsViewController.h
#interface SubSettingsViewController ()
#property MySettings *settings;
#end
SubSettingsViewController.m
#implementation SubSettingsViewController
- (void) viewWillDisappear: (BOOL) animated {
[super viewWillDisappear: animated];
// Set values for the appropriate properties in 'self.settings'
[self.settings setValue1: self.textField1.text];
}
Got a question, I'm trying to return to a previous view and share some data over to the frame I'm returning to. The data will be date and time and I would like to send this to a textField.
For example I'm calling the date *returneddate and the textField I'm calling *dateTime. The views are call *PickDateTime and SubmitEventsP2.
If you need more information just ask me and I'll add it if I can to make it easier for you to help me.
I'm using Xcode 4.2.
Ok.. its pretty simple.. you should use a delegate... if i understood correctly, you are on a secondary view and when you return to the main view you wish to send the data from the second view back to the main view, right?
so, in your second view, in the .h file, on top of interface, you will declare the delegate with:
#class nameOfTheViewController;
#protocol nameOfTheViewControllerDelegate <NSObject>
-(void)methodNameOfDelegateReturning:(NSString *)string otherString:(NSString *)string2;
#end
And in your interface, still in the .h, you will create a reference of this delegate like:
#property(nonatomic, weak) id <nameOfTheViewControllerDelegate> delegate;
after that, in your .m of nameOfTheViewController you will do:
#synthesize delegate = _delegate;
After you created you delegate in the nameOfTheViewController file, you will call the delegate method you just created exactly where and when you want to return to the previous view, filling it with the parameters you want to pass back... and of course, in your mainViewController, right in your didPrepareForSegue method, you will create a instance of the nameOfTheViewController class and set its delegate proeprty to self... for this to be possible, in your mainViewController .h you must conform to the nameOfTheViewControllerDelegate protocol.
I have a static singleton class that I use to access the main UIViewController (which is created by the appdelegate), and through it all sub-UIViewControllers.
Here's how I declare it
#interface mySingleton : NSObject
{
ViewController* m_viewController;
}
#property (nonatomic,assign) ViewController* m_viewController
And in the .m file, I get this error:
#synthesize m_viewController; // ERROR: Existing ivar "m_viewController" for unsafe_unretained property "m_viewController" must be __unsafe_unretained.
I solve this by putting __unsafe_unretained in the declaration as the error says, however..
is there any problems for me keeping a __unsafe_unretained property on the m_viewController? It represents the main menu of the app, and should never be deallocated. So it being a dangling pointer should never a problem due to it being released by the AppDelegate later on, right?
If you don't want m_viewController to be released, why not use strong instead of assign?
Also, since it's generally the app delegate that allocates the main view controller, and since the app delegate is accessible via the UIApplication singleton, why not keep the reference to the main view controller there instead of creating a separate class just to do that?