maintain object state when moved away of the screen - ios

I have a class declaration which contains an singleton object that manages the data (called sharedDatacontroller).
Now there are many other screen and declaration is the last one. I have to check if the user moves back from declaration screen and alters any data , then have to reset a switch button on the declaration screen.
My Approach:
-(void) viewWillDisappear:(BOOL)animated
{
self.sharedControllerClone=sharedController;
}
-(void) viewWillAppear:(BOOL)animated
{
if ([self.sharedControllerClone isEqual:sharedController])
{
NSLog(#"Not Same");
self.acceptDeclarationSwitch.on= self.acceptDeclarationSwitch.on;
}
else
{
self.acceptDeclarationSwitch.on= !self.acceptDeclarationSwitch.on;
}
}
But when the control comes in after navigating from back screen , the self.sharedControllerClone is reseting to Nil. How to preserve its state..any ideas?
Hope I am clear this time.

You can try this thing by creating Macros in your AppDelegate and assigning different states to a property taken in AppDelegate so that you will come to know that what is your current state. You can create an object of your AppDelegate in your required controllers and in their ViewDidLoad, you can assign the current state to AppDelegate like this:
//in AppDelegate
#import <UIKit/UIKit.h>
#define FIRST_CONTROLLER 1
#define SECOND_CONTROLLER 2
#define THIRD_CONTROLLER 3
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property int previousControllerState;
#end
And then, you can set your previousControllerState in the ViewDidLoad of your required controller.
//in your ViewControllers
- (void)viewDidLoad
{
[super viewDidLoad];
app.previousControllerState = FIRST_CONTROLLER;
}
And you can check your state in if condition in the next controller.
You have to take the states in AppDelegate to prevent the objects from getting nil. Otherwise, as soon as you move from one controller to another, the object of the previous controller might be getting nil.

Related

iOS More Than One Unwind Segues on a Button

In my app I have a Done button.
Depending on which screen the user came from (namely a saved list screen or a new list screen) I'd like the Done button to use a different unwind segue.
Is this possible - if so how?
Thanks.
I am new to IOS, but as per my knowledge, the simplest thing you can do is to create macros in your AppDelegate with different states and set a property whose value will be set according to those states, so that you can perform segue depending on the current status of the property. You can do like this:
//in AppDelegate.h
#import <UIKit/UIKit.h>
#define SAVED_LIST_SCREEN 1
#define NEW_LIST_SCREEN 2
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) int previousScreen;
#end
You can set the property "previousScreen" as SAVED_LIST_SCREEN or NEW_LIST_SCREEN depending on your current screen. And then you can check in "if codition" whether the previous state is Saved List or New List. And you can perform the segue operation accordingly.
if(app.previousScreen == SAVED_LIST_SCREEN)
{
//perform 1st segue
}
else
{
//perform 1st segue
}
Check it out and please let me know if it works.

Why isn't my delegate object responding to method calls?

I ultimately want to write an iOS app incorporating ALAssetsLibrary, but as a first step toward understanding delegation, I'm trying to pass a simple message between two view controllers. For some reason, I can't seem to get the message to pass. In particular, the delegate object (derpy) doesn't appear to exist (if(self.derpy) returns NO)).
I asked the same question on the Apple forums and was told that I should be using segues and setting properties / calling methods using self.child instead, but that seems strange. If I were to pass messages using the parent / child properties, would I still be able to create my views in Interface Builder? Once I have my two views set up, say inside a UINavigationController, I'm not sure how to actually "wire them up" so I can pass messages between them. Sorry if the question is overly broad.
Here's the controller I'm declaring the protocol in (called PickerViewController):
Interface:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#protocol DerpDelegate <NSObject>
#required
- (void) test;
#end
#interface PickerViewController : UIViewController
#property (nonatomic, assign) id<DerpDelegate> derpy;
#end
Implementation:
#import "PickerViewController.h"
#interface PickerViewController ()
#end
#implementation PickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.derpy) { // If the delegate object exists
[self.derpy test]; // send it this message
} else {
NSLog(#"Still not working."); // This always returns (i.e., self.derpy doesn't exist)
}
}
Delegate controller (MainViewController) interface:
#import <UIKit/UIKit.h>
#import "PickerViewController.h"
#interface MainViewController : UIViewController <DerpDelegate> // public promise to implement delegate methods
#property (strong, nonatomic) PickerViewController *picker;
- (void) test;
#end
And lastly, the delegate controller (MainViewController) implementation:
#import "MainViewController.h"
#import "PickerViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
// Here's that method I promised I'd implement
- (void) test{
NSLog(#"Test worked."); // This never gets called
}
- (void)viewDidLoad {
[super viewDidLoad];
self.picker.derpy = self;
//lazy instantiation
- (PickerViewController *) picker{
if(!_picker) _picker = [[PickerViewController alloc]init];
return _picker;
}
EDIT: Many thanks to rydgaze for pointing me in the right direction with self.picker.derpy = self, but for some reason, things still aren't working properly. Importantly, once that property has been set, if(self.picker.derpy) returns YES from MainViewController. But if(self.derpy) is still returning NO when called from inside the PickerViewController's viewDidLoad. How can the property exist and not exist at the same time?
You need to be sure that you're setting the delegate on the instance of the view controller that you put on screen. If you're using a navigation controller and segues to go between MainViewController and PickerViewController, then you should set the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.picker = (PickerViewController *)segue.destinationViewController;
self.picker.derpy = self;
}
You need to populate the delegate first.
Basically, your MainViewController shoudl at somepoint do a
picker.derpy = self;
Then when the delegate fires in PickerViewController, the callback will happen.
Edit:
A good practice is to do something like in PickerViewController
#property (nonatomic, assign) id<DerpDelegate > derpy;
and in your MainViewController indicate that you will implement the delegate
#interface MainViewController : UIViewController<DerpDelegate>
Eventually in your implementation of MainViewController
You will have something like
picker = [[PickerViewController alloc]init];
picker.derpy = self;
[picker doYourThing];
Once picker is all done, it may want to return results using the delegate.

Unable to set custom protocol delegate using ARC with two UITableViewControllers using UINavigationController

I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers. My delegate continues to return nil. Due to this, my required method is never called.
I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?
It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).
The nav is --> AlarmViewController --> AlarmDetailsViewController. I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.
NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.
AlarmDetailsViewController.h
#import "Alarm.h"
#protocol PassAlarmArray <NSObject>
#required
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
#end
#interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
//.....
id <PassAlarmArray> passAlarmsArrayDelegate;
}
#property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;
#end
AlarmDetailsViewController.m
#import "AlarmDetailsViewController.h"
#interface AlarmDetailsViewController ()
#end
#implementation AlarmDetailsViewController
#synthesize passAlarmsArrayDelegate;
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"delegate = %#", self.passAlarmsArrayDelegate); // This prints nil
[[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray];
}
//....
#end
AlarmViewController.h
#interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController *alarmDetailsViewController;
}
#property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;
#end
AlarmViewController.m
#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"
#interface AlarmViewController ()
#end
#implementation AlarmViewController
#synthesize alarmDetailsViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// This is where I'm attempting to set the delegate
alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
[alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}
//....
//My #required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray
{
alarmsTableArray = theAlarmsArray;
NSLog(#"alarmsTableArray contains: %#", alarmsTableArray); // Never gets called due to delegate being nil
NSLog(#"theAlarmsArray contains: %#", theAlarmsArray); // Never gets called due to delegate being nil
}
#end
I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.
I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.
You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AlarmDetailsViewController *alarm = segue.destinationViewController;
alarm.passAlarmsArrayDelegate = self;
}
You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.
Did you try replace (nonatomic, retain) with (nonatomic, strong) since you are using ARC?
Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, e.g. _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the #interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.
Just delete your alarmDetailsViewController ivar and use the #property, preferably through self.alarmDetailsViewController.

protocol method not being entered when called from delegate

I am having some issues with my protocol & delegate that I have set up in my app.
I am trying to return some data from a class back to a viewcontroller, however when I try to send it back nothing happens... The protocol method is never entered.
I have been over the way have set it up several times using this as a reference and just cannot see where I am making the error, So I thought if I share my code maybe someone here might be able to see what I cannot.
Heres the code I have written.
SendingClass.h
#protocol SearchViewCachedData <NSObject>
- (void)sendMyArray:(NSArray *)array;
#end
//..
__weak id <SearchViewCachedData> SearchViewDelegate;
//..
#property (weak, nonatomic) id <SearchViewCachedData> SearchViewDelegate;
//..
SendingClass.m
#synthesize SearchViewDelegate;
//..
[[self SearchViewDelegate]sendMyArray:dictionaryArray];
SearchView.h
#interface SearchViewController : UITableViewController <SearchViewCachedData> {
SearchView.m
- (void)sendMyArray:(NSArray *)array
{
//Break point in here.. but its never reached.
}
Going abit bonkers here so any help what so ever would be greatly appreciated.
I have a feeling your delegate is not set
Check to make sure searchViewDelegate is set to an instance value
if (self.searchViewDelegate != nil) {
[self.searchViewDelegate sendArray:array];
}
Also. Properties should have their first case lower case. Classes are the items that are Capitalized.
amendment
It may be getting set to nil by another part in code or you may not be setting it at all.
where you synthesize your delegate you can create a setter as well.
#synthesize searchViewDelegate = _searchViewDelegate;
- (void) setSearchViewDelegate:(id<SearchViewCachedData>) searchViewDelegate{
if (searchViewDelegate != searchViewDelegate){ // Add breakpoint here to see when set is called.
searchViewDelegate = searchViewDelegate;
}
}

What is a "delegate" in Objective C's iPhone development? [duplicate]

This question already has answers here:
How do I create delegates in Objective-C?
(20 answers)
Closed 9 years ago.
What is a "delegate" in Objective C's iPhone development?
A delegate is a pointer to an object with a set of methods the delegate-holder knows how to call. In other words, it's a mechanism to enable specific callbacks from a later-created object.
A good example is UIAlertView. You create a UIAlertView object to show a short message box to users, possibly giving them a choice with two buttons like "OK" and "Cancel". The UIAlertView needs a way to call you back, but it has no information of which object to call back and what method to call.
To solve this problem, you can send your self pointer to UIAlertView as a delegate object, and in exchange you agree (by declaring the UIAlertViewDelegate in your object's header file) to implement some methods that UIAlertView can call, such as alertView:clickedButtonAtIndex:.
Check out this post for a quick high-level intro to the delegate design pattern and other callback techniques.
References:
UIAlertView class reference
UIAlertViewDelegate class reference
Apple's guide to Delegates and Data sources
See this discussion
A delegate allows one object to send messages to another object when an event happens. For example, if you're downloading data from a web site asynchronously using the NSURLConnection class. NSURLConnection has three common delegates:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
One or more of these delegates will get called when NSURLConnection encounters a failure, finishes successfully, or received a response from the web site, respectively.
Delegates are a design pattern; there is no special syntax or language support.
A delegate is just an object that another object sends messages to when certain things happen, so that the delegate can handle app-specific details the original object wasn't designed for. It's a way of customizing behavior without subclassing.
I think this Wikipedia article describes it best: http://en.wikipedia.org/wiki/Delegation_pattern
It is "just" an implementation of a design pattern and very common in Objective-C
I think all these answers make a lot of sense once you understand delegates. Personally I came from the land of C/C++ and before that procedural languages like Fortran etc so here is my 2 min take on finding similar analogues in C++ paradigm.
If I were to explain delegates to a C++/Java programmer I would say
What are delegates ? These are static pointers to classes within another class. Once you assign a pointer, you can call functions/methods in that class. Hence some functions of your class are "delegated" (In C++ world - pointer to by a class object pointer) to another class.
What are protocols ? Conceptually it serves as similar purpose as to the header file of the class you are assigning as a delegate class. A protocol is a explicit way of defining what methods needs to be implemented in the class who's pointer was set as a delegate within a class.
How can I do something similar in C++? If you tried to do this in C++, you would by defining pointers to classes (objects) in the class definition and then wiring them up to other classes that will provide additional functions as delegates to your base class. But this wiring needs to be maitained within the code and will be clumsy and error prone. Objective C just assumes that programmers are not best at maintaining this decipline and provides compiler restrictions to enforce a clean implementation.
I try to elaborate it through simple program
Two Classes
Student.h
#import <Foundation/Foundation.h>
#interface Student : NSObject
#property (weak) id delegate;
- (void) studentInfo;
#end
Student.m
#import "Student.h"
#implementation Student
- (void) studentInfo
{
NSString *teacherName;
if ([self.delegate respondsToSelector:#selector(teacherName)]) {
teacherName = [self.delegate performSelector:#selector(teacherName)];
}
NSLog(#"\n Student name is XYZ\n Teacher name is %#",teacherName);
}
#end
Teacher.h
#import <Foundation/Foundation.h>
#import "Student.h>
#interface Teacher: NSObject
#property (strong,nonatomic) Student *student;
- (NSString *) teacherName;
- (id) initWithStudent:(Student *)student;
#end
Teacher.m
#import "Teacher.h"
#implementation Teacher
- (NSString *) teacherName
{
return #"ABC";
}
- (id) initWithStudent:(Student *)student
{
self = [ super init];
if (self) {
self.student = student;
self.student.delegate = self;
}
return self;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Teacher.h"
int main ( int argc, const char* argv[])
{
#autoreleasepool {
Student *student = [[Student alloc] init];
Teacher *teacher = [[Teacher alloc] initWithStudent:student];
[student studentInfo];
}
return 0;
}
EXPLANATION :::
From main method when initWithStudent:student will execute
1.1 Teacher's object's property 'student' will be assigned with student object.
1.2 self.student.delegate = self
means student object's delegate will points to teacher object
From main method when [student studentInfo] will be called
2.1 [self.delegate respondToSelector:#selector(teacherName)]
Here delegate already points to teacher object so it can invoke
'teacherName' instance method.
2.2 so [self.delegate performSelector:#selector(teacherName)]
will execute easily.
It looks like Teacher object assign delegate to student object to call it's own method.
It is a relative idea, where we see that student object called 'teacherName' method but it is basically done by teacher object itself.
Please! check below simple step by step tutorial to understand how Delegates works in iOS.
Delegate in iOS
I have created two ViewControllers (for sending data from one to another)
FirstViewController implement delegate (which provides data).
SecondViewController declare the delegate (which will receive data).
Here is the sample code may help you.
AppDelegate.h
#import <UIKit/UIKit.h>
#class FirstViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FirstViewController *firstViewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "FirstViewController.h"
#implementation AppDelegate
#synthesize firstViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//create instance of FirstViewController
firstViewController = [[FirstViewController alloc] init];
//create UINavigationController instance using firstViewController
UINavigationController *firstView = [[UINavigationController alloc] initWithRootViewController:firstViewController];
//added navigation controller to window as a rootViewController
self.window.rootViewController = firstView;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface FirstViewController : UIViewController<MyDelegate>
#property (nonatomic, retain) NSString *mesasgeData;
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UIButton *nextButton;
- (IBAction)buttonPressed:(id)sender;
#property (nonatomic, strong) SecondViewController *secondViewController;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize mesasgeData;
#synthesize textField;
#synthesize secondViewController;
#pragma mark - View Controller's Life Cycle methods
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Button Click event handling method
- (IBAction)buttonPressed:(id)sender {
//get the input data from text feild and store into string
mesasgeData = textField.text;
//go keypad back when button clicked from textfield
[textField resignFirstResponder];
//crating instance of second view controller
secondViewController = [[SecondViewController alloc]init];
//it says SecondViewController is implementing MyDelegate
secondViewController.myDelegate = self;
//loading new view via navigation controller
[self.navigationController pushViewController:secondViewController animated:YES];
}
#pragma mark - MyDelegate's method implementation
-(NSString *) getMessageString{
return mesasgeData;
}
#end
SecondViewController.h
//declare our own delegate
#protocol MyDelegate <NSObject>
-(NSString *) getMessageString;
#end
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
#property (nonatomic, retain) id <MyDelegate> myDelegate;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize messageLabel;
#synthesize myDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
messageLabel.text = [myDelegate getMessageString];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
The delegate fires the automatic events in Objects C. If you set the delegate to Object, it sends the message to another object through the delegate methods.
It's a way to modify the behavior of a class without requiring subclassing.
Each Objects having the delegate methods.These delegate methods fires, when the particular Objects take part in user interaction and Program flow cycle.
Simply stated: delegation is a way of allowing objects to interact with each other without creating strong interdependencies between them.
A delegate captures the taping actions of an user and performs particular Action according to the user Taping Action.
Delegate is nothing but instance of Object which we can call methods behalf of that Objects. and also helps to create methods in rumtime of that Objects.

Resources