I am new to iPhone. I am trying to implement KVO mechanism.
What I have?
two TabController with two UIViewController, FirstViewController has a button,
SecondViewController has a UITextView
What I Want?
When button is pressed in the firstViewController, it updates member variable, which should be observed by secondViewController, and it should append to the UITextView.
What I did?
FirstViewController.h
#interface FirstViewController : UIViewController
{
IBOutlet UIButton *submitButton;
}
-(IBAction)submitButtonPressed;
#property (retain) NSString* logString;
#end
FirstViewController.m
-(IBAction)submitButtonPressed
{
NSLog (#" Submit Button PRessed ");
self.logString = #"... BUtton PRessed and passing this information ";
}
SecondViewController.h
#interface SecondViewController : UIViewController
{
IBOutlet UITextView *logView;
}
#property (nonatomic, strong) UITextView *logView;
#end
SecondViewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
......
NSArray *vControllers = [self.tabBarController viewControllers];
FirstViewController *fvc = [vControllers objectAtIndex:0];
[fvc addObserver:self forKeyPath:#"logString" options:NSKeyValueObservingOptionNew context:NULL];
return self;
}
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog (#".... OBSERVE VALUE FOR KEY PATH...");
}
What output I Expect?
The String ".... OBSERVE VALUE FOR KEY PATH..." should be printed each time i press the button in the FirstViewController.
What I get?
No OUtput.
What i am doing wrong?. Kindly help me
put your "member variable" into a separate class file ... i.e. MODEL / view / controller. Make a singleton model object holding your data, then you can KVO that model object from any view controller.
This is roughed out pseudo-code:
#interface MyDataModel: NSObject
{
NSString *logString;
}
#property (nonatomic,retain) NSString *logString;
#end
#implementation MyDataModel
#synthesize logString;
+ (MyDataModel *) modelObject
{
static MyDataModel *instance = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
if (instance == nil)
{
instance = [[self alloc] init];
}
});
return (instance);
}
#end
in your VC1
MyDataModel *model = [MyDataModel modelObject];
[model setLogString:#"test"];
in your VC2
[model addObserver:self forKeyPath:#"logString" options:0 context:NULL];
a more sophisticated approach would use Core Data as a persistent store and to act as your data model.
Related
I have created a main dialog (MainMenu.xib) and created two button on mainmenu.xib file and when click on each button, it will launch different xib file(say for button1 xib file is button1.xib and for button2 xib file is button2.xib file).
Now, My question I need the value of button1.xib file into button2.xib file.
I have tried the code
id appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate] ;
this code always gives the delegate of active dialog.
Can you please tell me how to get the control or object of inactive dialog?
Thanks,
What you need is model object. Below is really simple approach how you should start. This model object should be stored in AppDelegate for non-document based app. Second window should not know about existence of any other window. The same applies for first window. It shouldn't know more that displaying/working with model.
Accessing model through delegate in fact accessing delegate like below is considered as really, really, really bad.
id model = [(AppDelegate*)[[NSApplication sharedApplication] delegate] model];
Simple example how you can implement model and monitor for changes
#import "AppDelegate.h"
#import "FirstWC.h"
#import "SecondWC.h"
#import "Model.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (nonatomic, strong) FirstWC *firstWC;
#property (nonatomic, strong) SecondWC *secondWC;
#property (nonatomic, strong) Model *model;
#end
#implementation AppDelegate
- (instancetype)init
{
self = [super init];
if (self) {
_model = [[Model alloc] init];
}
return self;
}
- (IBAction)changeColor:(id)sender
{
NSUInteger number = arc4random() % 4;
switch (number) {
case 0:
self.model.color = [NSColor redColor];
break;
case 1:
self.model.color = [NSColor blueColor];
break;
case 2:
self.model.color = [NSColor purpleColor];
break;
case 3:
self.model.color = [NSColor yellowColor];
break;
default:
break;
}
}
- (IBAction)showFirstWC:(id)sender
{
if (!_firstWC) {
_firstWC = [[FirstWC alloc] initWithModel:self.model];
}
[[_firstWC window] makeKeyAndOrderFront:self];
}
- (IBAction)showSecondWC:(id)sender
{
if (!_secondWC) {
_secondWC = [[SecondWC alloc] initWithModel:self.model];
}
[[_secondWC window] makeKeyAndOrderFront:self];
}
#end
Model:
#import <Cocoa/Cocoa.h>
#interface Model : NSObject
#property (nonatomic, strong) NSColor *color;
#end
#import "Model.h"
#implementation Model
- (instancetype)init
{
self = [super init];
if (self) {
_color = [NSColor blueColor];
}
return self;
}
#end
Window Controller:
#import "FirstWC.h"
#import "Model.h"
#interface FirstWC ()
#property (nonatomic, strong) Model *model;
#end
#implementation FirstWC
- (instancetype)initWithModel:(Model *)model
{
self = [super initWithWindowNibName:#"FirstWC"];
if (self) {
_model = model;
[self addObserver:self
forKeyPath:#"model.color"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
self.window.backgroundColor = [self model].color;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:#"model.color"]) {
self.window.backgroundColor = self.model.color;
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"model.color"];
}
#end
#import "SecondWC.h"
#interface SecondWC ()
#property (nonatomic, strong) Model *model;
#end
#implementation SecondWC
- (instancetype)initWithModel:(Model *)model
{
self = [super initWithWindowNibName:#"SecondWC"];
if (self) {
_model = model;
[self addObserver:self
forKeyPath:#"model.color"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
self.window.backgroundColor = [self model].color;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:#"model.color"]) {
self.window.backgroundColor = self.model.color;
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"model.color"];
}
#end
Add properties for both button1 and button2 in your controller, and a (weak) property for button2 in the button1 controller, and vice versa.
- (void)createButtons {
DlgController1 = [[Button1 alloc] initWithWindowNibName:#"Button1"];
DlgController2 = [[Button2 alloc] initWithWindowNibName:#"Button2"];
DlgController1.button2 = DlgController2;
DlgController2.button1 = DlgController1;
}
- (IBAction)Button1:(id)sender {
[DlgController1 showWindow:self];
[NSApp runModalForWindow:DlgController1.window];
[NSApp endSheet:DlgController1.window];
[DlgController1.window orderOut:self];
[DlgController1 close];
}
I have tried the code
id appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate] ;
this code always gives the delegate of active dialog.
I'm not quite sure how this relates to the rest of your question, but the above issue suggests that you have an instance of your AppDelegate class in button1.xib and button2.xib. You should not.
There is only one application object in your app. It should have only one delegate. That instance is created in the MainMenu NIB and connected to the application's delegate outlet using the File's Owner placeholder's outlet. That should be the only instance of AppDelegate in your whole app.
If you also create an instance of AppDelegate in the other NIBs, then there will be multiple instances of that class once those NIBs are loaded, which will just confuse things. Also, if those instances are also connected to the application's delegate outlet, then they will replace the original delegate. That explains the symptom you described above where [[NSApplication sharedApplication] delegate] gives an object from the last NIB to load.
I'm not sure what button1.xib and button2.xib are supposed to contain. I'm guessing they are supposed to contain a window. In that case, you should write a custom subclass of NSWindowController to be the window controller for each window NIB. You would instantiate that class in the button's action method and provide it with whatever information it needs (possibly including a reference to the app delegate). That controller class would be responsible for loading the NIB. It would serve as the NIB's owner and would be represented in the NIB by the File's Owner placeholder. It's pretty common to make the window controller be the window's delegate, too. I recommend that you follow the advice of this blog post.
I'm just trying to understand how delegate works and I'm in troubles.
I have two classes (both UIViewController) connected into the storyboard, the first one (ViewController.h/m) hold a TableView with cells and the second one (AddNameViewController.h/m) simply hold a TextField (where I want to write) and a button (Add Name)
as you surely understand I want the button pressed to send to the TableView what is written into the TextField, pretty simple.
And since I have two different Controllers and an Array containing the data holds by the tableview, I want to connect them with a delegate (just to learn it).
here is some code:
ViewController.h
#import "AddNameViewController.h"
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, AddNameViewControllerDelegate>
#property (strong, nonatomic) NSMutableArray *array;
#end
ViewController.m
#import "ViewController.h"
#import "AddNameViewController.h"
#inferface ViewController ()
#end
#implementation ViewController
#synthesize array;
-(void)addStringWithString:(NSString*)string
{
[self.array addObject:string];
NSLog(#"%#", array);
}
-(void)viewDidLoad
{
AddNameViewController *anvc = [[AddNameViewController alloc] init];
anvc.delegate = self;
array = [[NSMutableArray alloc] initWithObjects:#"first", #"second", nil];
NSLog(#"%#", array);
[super viewDidLoad];
}
-(NSInteger)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSindexPath*)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
#end
AddNameViewController.h
#protocol AddNameViewControllerDelegate <NSObject>
-(void)addStringWithString:(NSString*)string;
#end
#interface AddNameViewController : UIViewController
#property (weak, nonatomic) id <AddNameViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITextField *myTextField;
-(IBAction)add:(id)sender;
#end
finally the AddNameViewController.m
#import "ViewController.h"
#interface AddNameViewController ()
#end
#implementation AddNameViewController
#synthesize myTextField, delegate;
-(id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(IBAction)add:(id)sender
{
[self.delegate addStringWithString:self.myTextField.text];
// I've also tried with this but nothing --> [self.delegate addStringWithString:#"aa"];
}
#end
The array is initialized properly, no errors, no warnings, no crashes, simply seems like the method "addStringWithString" is not even called, because is not even NSLog anything.
obviously everything in connected in the storyboard, methods and outlets, thanks for your help.
in interface builder of AddNameViewController, did you connect the button event (Touch Up inside) into the action -(IBAction)add:(id)sender ?
also try this
-(IBAction)add:(id)sender
{
if([self.delegate respondsToSelector:#selector(addStringWithString:)]) {
[self.delegate addStringWithString:self.myTextField.text];
}
// I've also tried with this but nothing --> [self.delegate addStringWithString:#"aa"];
}
I have a simple utility app, with a MainViewController.m & h and a FlipsideViewController.m & h. Within my storyboard I have a button on MainViewController. I want to be able to click the button and run a method in FlipsideViewController.m is this possible? this is my first app and I am a total novice. all comments / suggestion welcome.
enter code here
i have this in my FlipsideViewController.m this is what i want to call when i click the button.
- (void)SaveFPQData
{
NSLog(#"Data Saved");
}
and this is what i have in MainViewController.m
- (IBAction)saveButton:(id)sender
{
}
This is the code I have so far;
MainViewController.h
#import "FlipsideViewController.h"
#import "sqlite3.h"
#import "FPQCheck.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameField;
#property (weak, nonatomic) IBOutlet UITextField *checkField;
#property (weak, nonatomic) IBOutlet UITextField *commentsField;
#property (weak, nonatomic) FlipsideViewController *flipsidecontroller;
- (IBAction)saveButton:(id)sender;
- (IBAction)showHistoryButton:(id)sender;
#end
MainViewController.m
#import "MainViewController.h"
#import "FlipsideViewController.h"
#import "sqlite3.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
[[segue destinationViewController] setDelegate:self];
}
}
- (IBAction)saveButton:(id)sender
{
[self.flipsidecontroller SaveFPQData];
//[[NSNotificationCenter defaultCenter] postNotificationName:#"SaveFPQData" object:nil];
}
- (IBAction)showHistoryButton:(id)sender
{
}
#end
FlipSideViewController.h
#import <UIKit/UIKit.h>
#import "FPQCheck.h"
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
#property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
-(void)SaveFPQData;
- (IBAction)done:(id)sender;
- (IBAction)deleteEntry:(id)sender;
#end
FlipSideViewController.m
#import "FlipsideViewController.h"
#import "MainViewController.h"
#interface FlipsideViewController ()
{
NSMutableArray *arrayOfCheck;
sqlite3 *fpqDB;
NSString *dbPathString;
}
#end
#implementation FlipsideViewController
- (void)viewDidLoad
{
/*
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(SaveFPQData)
name:#"SaveFPQData"
object:nil];
*/
[super viewDidLoad];
arrayOfCheck = [[NSMutableArray alloc]init];
[self creatOrOpenDB];
[[self myTableView]setDelegate:self];
[[self myTableView]setDataSource:self];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)SaveFPQData
{
NSLog(#"Data Saved");
}
-(void)creatOrOpenDB
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"FPQ.db"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath = [dbPathString UTF8String];
//create db
if (sqlite3_open(dbPath, &fpqDB)==SQLITE_OK) {
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS FPQ (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, CHECK INTEGER, COMMENTS TEXT)";
sqlite3_exec(fpqDB, sql_stmt, NULL, NULL, &error);
sqlite3_close(fpqDB);
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];}
- (IBAction)deleteEntry:(id)sender {
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayOfCheck count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
FPQCheck *fpqCheck = [arrayOfCheck objectAtIndex:indexPath.row];
NSString *nameANDcheck = [NSString stringWithFormat:#"%#%d", fpqCheck.name, fpqCheck.check];
cell.textLabel.text = nameANDcheck;
cell.detailTextLabel.text = fpqCheck.comments;
return cell;
}
#end
You have mainly two ways:
add a property (eg. self.flipSideController) to your MainViewController to store a reference to the FlipsideViewController; then call SaveFPQData though it (eg. [self.flipSideController SaveFPQData]; or
use notification center to post a notification from saveButton: that triggers SaveFPQData; this would go like this:
//-- in flipsidecontroller `viewDidLoad`:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(SaveFPQData)
name:#"SaveFPQData"
object:nil];
//-- in saveButton:
[[NSNotificationCenter defaultCenter] postNotificationName:#"SaveFPQData" object:nil];
The second method is the simplest to implement, IMO, and it allows for the loosest coupling, at the expense of some clock cycles.
EDIT:
It is not entirely clear to me what you are trying to do (specifically, I don't understand fully how you can push the button in MainViewController once you FlipsideViewController is displayed; on the other hand, if you do not segue to the FlipsideViewController, then it is not there, so you cannot send a message to it), anyway you could try and initialise your self.flipsideViewController property in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
UIViewController* controller = [segue destinationViewController];
[controller setDelegate:self];
if ([controller isKindOfClass:[FlipsideViewController class]])
self.flipsideViewController = (id)controller;
}
}
after doing that, your MainViewController will be able to send the saveFPQ message to the FlipsideViewController.
If you mean you would like to send the saveFPQ message before segue-ing to the FlipsideViewController, you should make the saveButton segue to it and the call the saveFPQ method.
What I suspect is you need some kind of "model" object accessible both from the main view and the flipside view controller.
Hope this helps.
Bah. I've pulled my hair out over this problem for the past couple days now, but I know I must be overlooking the obvious. I've made my PickerViewController(.h./m) and PickerViewAppDelegate(.h/.m) files and they run fine as a standalone program, but I would like to have the picker pop up after a procedureal event occurs in my "helloworld.m" file. I can get the picker to show up, but I cannot for the life of me figure out how to populate it so that it isn't blank. I THINK I've done everything right up until I try to pass my array to my pickerview object. What am I doing wrong?
PickerViewController.h
#import <UIKit/UIKit.h>
#interface PickerViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
IBOutlet UIPickerView *pickerView;
NSMutableArray *scrollerData;
}
#property (nonatomic, retain) IBOutlet UIPickerView *pickerView;
#property (nonatomic, retain) NSMutableArray *scrollerData;
-(void)setScrollerData:(NSMutableArray *)array;
#end
PickerViewController.m
#import "PickerViewController.h"
#implementation PickerViewController
#synthesize pickerView, scrollerData;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
// [arrayColors release];
[super dealloc];
}
-(void)setScrollerData:(NSMutableArray *)array
{
//[self.scrollerData arrayByAddingObjectsFromArray:array];
scrollerData = array;
}
#pragma mark -
#pragma mark Picker View Methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [scrollerData count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [scrollerData objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSLog(#"Selected Number: %#. Index of selected numbers: %i", [scrollerData objectAtIndex:row], row);
}
PickerViewAppDelegate.h
#import <UIKit/UIKit.h>
#class PickerViewController;
#interface PickerViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
PickerViewController *pvController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
PickerViewAppDelegate.m
#import "PickerViewAppDelegate.h"
#import "PickerViewController.h"
#implementation PickerViewAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
pvController = [[PickerViewController alloc] initWithNibName:#"PickerView" bundle:[NSBundle mainBundle]];
[window addSubview:pvController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
- (void)dealloc {
[pvController release];
[window release];
[super dealloc];
}
#end
Helloworld.m
...
UIView* view = [[CCDirector sharedDirector] openGLView];
UIPickerView *pickerView=[[UIPickerView alloc] init];
pickerView.frame=CGRectMake(100,100, 200, 200);
NSMutableArray *arrayNumbers = [[NSMutableArray alloc] init];
[arrayNumbers addObject:#"30"];
[arrayNumbers addObject:#"31"];
[arrayNumbers addObject:#"32"];
[arrayNumbers addObject:#"33"];
[arrayNumbers addObject:#"34"];
[arrayNumbers addObject:#"35"];
[arrayNumbers addObject:#"36"];
[pickerView setscrollerData: arrayNumbers];//Should I be calling pickerView here or something else?
[view addSubview: pickerView];
pickerView.hidden=NO;
...
You have overridden the setter method generated by #synthesize in PickerViewController, so you are no longer retaining it.
Then, you are calling setScrollerData on your pickerView (this should be giving you a warning or crashing since pickerView doesn't respond to that method).
You are not setting PickerViewController as the delegate or datasource of your picker view in helloworld.m.
I can't see where your hello world code fits in. It seems to be adding a new picker view rather than using the one from the xib of PickerViewController. You should be instantiating pickerviewcontroller from your hello world and adding its .view as a subview or presenting it as a modal view controller rather than setting up a new picker view. You can then pass your array to the instance of pickerviewcontroller. Note though that it is not standard to have a separate view controller for what is essentially a subview, though I don't have much knowledge of cocos2d so I don't know if this is normal when using that framework.
Well, i think you should just pass the array from HelloWorld class to PickerViewController class using property/synthesize.
This is so basic that hopefully it will get a response. I could not find an example to model after. I essentially want to have a NSMutableDictionary that is cleared/deleted when the view is called. Have a button add an integer and a separate button remove the integer. There is a final button to save the dictionary to NSUserDefaults and return to the previous view. Do I need to call on the dictionary in each IBAction or in the viewDidLoad to first create it and then reference it? Please advise.
example.h
#interface example : UIViewController {
NSMutableDictionary *exampleDict;
UIButton *B1;
UIButton *B2;
UIButton *Bdone
}
-(IBAction)button1;
-(IBAction)button2;
-(IBAction)done;
#property (retain,nonatomic) IBOutlet UIButton *B1;
#property (retain,nonatomic) IBOutlet UIButton *B2;
#property (retain,nonatomic) IBOutlet UIButton *Bdone;
#property (retain,nonatomic) NSMutableDictionary *exampleDict;
#end
example.m
#implementation example
#synthesize exampleDict;
#synthesize B1;
#synthesize B2;
#synthesize Bdone;
#end
-(IBAction)button1{
[exampleDict setValue:[NSNumber numberWithInt:1] forKey:#"one"];
}
-(IBAction)button2 {
[exampleDict removeObjectforKey: #"one"];
}
-(IBAction)done {
[[NSUserDefaults standardUserDefaults] setObject:exampleDict forKey:#"dictionaryKey"];
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
-(void)viewDidLoad {
}
- (void)dealloc{
[B1 release];
[B2 release];
[Bdone release];
}
I don't see any initialization of the array. You should initialize it before you can message to it. You will also have to check if the value exists in the user defaults. If it exists, you should use it otherwise create it.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
exampleDict = [[[NSUserDefaults standardUserDefaults] objectForKey:#"dictionaryKey"] mutableCopy];
if ( !exampleDict ) {
exampleDict = [[NSMutableDictionary alloc] init];
}
}
In addition to this, you might want to call synchronize on the user defaults and release exampleDict in the dealloc method.