Using UIButtons to create/remove/save a NSMutableDictionary to NSUserDefaults - objective-c

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.

Related

how to delegate with an IBAction between two different UIViewController

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"];
}

NSArrayController does not update content for second window

I'm writing an OSX app where a second window is opened to show results when the button on the first window is pushed. The window-2 start fine and shows what I want. But when I change inputs in window-1 and hit the action button again the window-2 doesn't update the results.
here my questions:
how does the content of window-2 update after input change in window-1
how is window-2 closed and released (right now window-2 shows up with the same content before closed when action button is pushed again)
here is the code for the action button:
- (IBAction)pushRun:(id)sender {
if (!rwc)
{
rwc = [[ResultWindowController alloc] init];
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result calculation
}
[rwc showWindow:self];
}
It might be easy but I'm afraid to always create an other ResultWindowController instance.
Thanks in advance.
Joerg
here is the ResultWindowController.h:
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController{
NSArray *valueArray;
NSMutableArray *resultArray;
NSNumber *numberOfCalculations;
}
#property (nonatomic, retain, readwrite) NSArray *valueArray;
#property (retain) NSNumber *numberOfCalculations;
#property (nonatomic, retain, readwrite) NSMutableArray *resultArray;
-(void)calculateResults;
#end
and here the ResultWindowController.m
#import "ResultWindowController.h"
#import "ResultItem.h" //my result model
#implementation ResultWindowController
#synthesize valueArray, resultArray, numberOfCalculations;
- (id)init
{
if(![super initWithWindowNibName:#"ResultWindow"])
return nil;
return self;
}
-(void)awakeFromNib
{
}
- (void)windowDidLoad
{
[super windowDidLoad];
}
- (void)calculateResults
{
//a lot of calculation code ...
ResultItem *newResult = [[ResultItem alloc]init];
[newResult setValue:[nameArray objectAtIndex:i] forKey:#"name"];
[newResult setValue:[NSNumber numberWithDouble:avg] forKey:#"averageValue"];
[newResult setValue:[NSNumber numberWithDouble:min] forKey:#"minValue"];
[newResult setValue:[NSNumber numberWithDouble:max] forKey:#"maxValue"];
[newResult setValue:dimensionRandomArray forKey:#"randomArray"];
[resultArray addObject:newResult];
}
resultarray is the content source for an arraycontroller in the ResultWindowController.xib. The arraycontroller is bound to a table view which is supposed to show the array content. This is not updated the second time.
I believe you must simply do the following:
- (IBAction)pushRun:(id)sender {
if (!rwc)
{
rwc = [[ResultWindowController alloc] init];
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result calculation
}
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result
[rwc showWindow:self];
}
You were only changing values of ResultWindowController if it did not exist. You want to change values no matter what, just not start a new instance. So, as long as you don't use [[alloc]init] you're good.
Hope that helps. If you need anything else, drop a comment.
Edit
To create a property for your tableView do the following:
In .h
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController{
NSArray *valueArray;
NSMutableArray *resultArray;
NSNumber *numberOfCalculations;
}
#property (nonatomic, retain, readwrite) NSArray *valueArray;
#property (retain) NSNumber *numberOfCalculations;
#property (nonatomic, retain, readwrite) NSMutableArray *resultArray;
#property (assign) NSTableView *yourTableView; //Add this code
-(void)calculateResults;
#end
and here the ResultWindowController.m
#import "ResultWindowController.h"
#import "ResultItem.h" //Your result model
#implementation ResultWindowController
#synthesize valueArray, resultArray, numberOfCalculations;
#synthesize yourTableView; //Add this code
Then you should be able to call [yourTableView reloadData]

iOS Passing (Retain) the value of an NSMutableArray to another NSMutableArray in another view

I'm using .XIB and without ARC. I'm passing the value of the NSMultableArray to another view, if I put [self presentModel...], it works, but if I call the AnotherView with a button the value of the NSMultableArray of the AnotherView is null!
AnotherView.h
#interface AnotherViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>{
NSMutableArray *otherAnother;
NSMutableArray *arrayOfTheAnotherView;
}
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) NSMutableArray *arrayOfTheAnotherView;
AnotherView.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
otherAnother = [[NSMutableArray alloc]init];
otherAnother = [[NSMutableArray alloc]initWithArray:self.arrayOfTheAnotherView];
//    [otherAnother addObjectsFromArray:arrayOfTheAnotherView];
NSLog(#"%#", self.arrayOfTheAnotherView);
}
The NSLog has written "null"
CurrentView.h
#interface CurrentViewController : UIViewController {
NSMutableArray * arrayCurrentView;
AnotherViewController *superAnotherView;
}
#property (retain, nonatomic) AnotherViewController *superAnotherView;
CurrentView.m
#synthesize superAnotherView;
NSString *x = [[NSString alloc]initWithFormat:#"%#",[label text]];
arrayCurrentView = [[NSMutableArray alloc]init];
[arrayCurrentView retain];
[arrayCurrentView addObject:x];
self.superAnotherView = [[AnotherViewController alloc]initWithNibName:nil bundle:nil];
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
[self.superAnotherView.arrayOfTheAnotherView addObjectsFromArray:arrayCurrentView];
I don't know how to retain the value of the NSMultableArray, thanks the help.
It is how I call the AnotherView:
UIButton *buttonAnother = [UIButton buttonWithType:UIButtonTypeCustom]; [buttonAnother setTag:5]; [buttonAnother addTarget:self action:#selector(switchTabBar:) forControlEvents:UIControlEventTouchDown];
[tabBarViewController.view addSubview:buttonAnother];
- (IBAction)switchTabBar:(id)sender { switch ([(UIButton *)sender tag]) { case 5: [self.tabBarController setSelectedIndex:0]; break; }
These should not be necessary:
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
Properties are already initialized when the class is initialized.
In fact, your explicit retain lines shouldn't be necessary at all; you're not releasing them as far as I can see and just making the retain count 2 so that it has to be released twice.
I think there's something going on here that the methods and view controllers are not being called in the order you want, probably something to do with the tab bar.
I dicoverd! I'm using the MVC
A array of the APP delegate don't lost its value.
AppDelegate
NSMutableArray *arrayDelegate;
View.m
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate.arrayDelegatePedido addObject:#"title"]; //for example

Passing value from one class to another, using #property

I have been pulling my hair out all afternoon trying to figure out why the following code will not work. All I am trying to do is pass a string, from one class to another.
In my FirstDetailViewController.h file I declare the NSString
#property(nonatomic, retain) NSString *infoForArray;
And then in my Grinding01_DetailViewController.m I try to set a value for the string
#import "Grinding01_DetailViewController.h"
#import "FirstDetailViewController.h"
#implementation Grinding01_DetailViewController
...
NSString *didLoadMessage = #"Grinding01 Loaded";
FirstDetailViewController *temp = [[FirstDetailViewController alloc] initWithNibName:#"FirstDetailView" bundle:nil];
temp.infoForArray = didLoadMessage;
[self.navigationController pushViewController:temp animated:YES];
}
When I output the infoForArray from the FirstDetailViewController.h it is null.
Any help would be appreciated, I think there's a simple step that I am missing, but I just can't see it.
EDIT: Here is the code from the FirstDetailViewController
FirstDetailViewController.h
#import <UIKit/UIKit.h>
#import "Protocols.h"
#interface FirstDetailViewController : UIViewController <SubstitutableDetailViewController> {
//for the output
IBOutlet UITextView *outputView;
UIToolbar *navigationBar;
NSMutableArray *logMessages;
}
#property (nonatomic, retain) IBOutlet UIToolbar *navigationBar;
//for incoming messages
#property(nonatomic, retain) NSString *infoForArray;
#end
FirstDetailViewController.m
#import "FirstDetailViewController.h"
#implementation FirstDetailViewController
#synthesize navigationBar, infoForArray;
-(void)viewDidLoad{
[super viewDidLoad];
//The log cannot be changed
outputView.editable = NO;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidUnload {
[super viewDidUnload];
self.navigationBar = nil;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
NSLog(#"message: %#", infoForArray);
outputView.text = infoForArray;
}
#pragma mark -
#pragma mark Managing the popover
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [navigationBar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[navigationBar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Remove the popover button from the toolbar.
NSMutableArray *itemsArray = [navigationBar.items mutableCopy];
[itemsArray removeObject:barButtonItem];
[navigationBar setItems:itemsArray animated:NO];
[itemsArray release];
}
#pragma mark -
#pragma mark Rotation support
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[navigationBar release];
[super dealloc];
}
#end
It sounds like the trouble area is in in FirstDetailViewController. I would suggest posting the code for that so we can see what's going on.
my guess is you are checking for infoForArray somewhere in the instantiation process of FirstDetailViewController, which occurs before you set temp.infoForArray = didLoadMessage.
Just for reference, if you check for infoForArray in viewDidLoad that will be too early. viewDidLoad is triggered when the view is put into memory. What you want is viewDidAppear, which you may have to add yourself

IBOutletCollection (UIbutton)

in my .h I have
IBOutlet NSMutableArray *buttons;
#property (nonatomic, retain) IBOutletCollection(UIButton) NSMutableArray *buttons;
-(void)play:(UIButton *)theButton;
in my .m I have
-(void)initButtons{
buttons = [[NSMutableArray alloc] initWithCapacity:1];
UIButton *myBut = [UIButton alloc];
[buttons addObject: myBut];
[[buttons objectAtIndex:0] addtarget:self action#selector(play:) forControlEventTouchUpInside];
}
...
-(void)dealloc{
[buttons dealloc];
[super deallloc];
}
.....
-(void)viewDidLoad{
[super viewDidLoad];
[self initButtons];
}
I dragged the buttons IBoutletCollection in interface builder to a simple button, but when I test it it doesn't perform the expected action;
I should mention that if I turn my action into (IBAction) instead of (void) and link it to the button it works;
I don't understand very well NSArrays and outlet collections.
The array is set for you with whatever buttons you've connected to the collection in the NIB. It fails to do anything because you've reset the ivar here:
buttons = [[NSMutableArray alloc] initWithCapacity:1];
…or because you've not connected buttons to the collection.
You don't need outlets to connect buttons to methods.
Get rid of all your outlet and property and initButtons code and just have this:
//in .h
-(IBAction)play:(UIButton *)theButton;
//in .m
-(IBAction)play:(UIButton *)theButton
{
//the code for your play action
}
Then in Interface Builder, ctrl-drag from the button to the File's Owner and select the play: action.
Declare your UIButton myBut as an IBOutlet with property in .h file.connect your button outlet in xib to myBut.No need to declare NSMutableArray as an IBOutletCollection or IBOutlet.You simply declare it and No need to allocate myBut again inside initButtons method.
You can do like this.
viewController.h
#property (strong, nonatomic) IBOutlet UIButton *myButton;
#property (nonatomic,strong) NSMutableArray *buttons;
-(void)initButtons;
-(void)play:(id)sender;
inSide xib connect your button outlet to myButton
viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self initButtons];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)initButtons{
buttons = [[NSMutableArray alloc] initWithCapacity:1];
[buttons addObject: myButton];
[[buttons objectAtIndex:0] addTarget:self action:#selector(play:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)play:(id)sender
{
NSLog(#"button tapped");
}