NSUserDefaults Unique To Each Item - nsuserdefaults

In my app, I have numerous plants using this type of code which works great except when I want the user to save their own notes unique for each plant they view...
In my PerennialDataPurple.h
// PerennialDataPurple.h
// Created by John Lein Feb. 2017.
// Copyright (c) 2017 Lein Design Inc. All rights reserved.
#interface PerennialDataPurple : NSObject
#property (nonatomic, strong) NSString* name;
#property (nonatomic, strong) NSString* namethumb;
...
#property (nonatomic, strong) NSString* image3Title;
*#property (nonatomic, strong) NSString* save_userNote;*
+(NSArray* )createMultipleSampleDishes;
#end
In my PerennialDataPurle.m I have the following code which works except again for saving notes...
// PerennialDataPurple.m
// Created by John Lein Feb. 2017.
// Copyright (c) 2017 Lein Design Inc. All rights reserved.
#import "PerennialDataPurple.h"
#implementation PerennialDataPurple
+(NSArray* )createSampleDishes{
PerennialDataPurple* purpleconeflower = [[PerennialDataPurple alloc] init];
purpleconeflower.name = #"Purple Cone Flower";
purpleconeflower.namethumb = #"Purple\rCone Flower";
...
purpleconeflower.image3Description = #"Put some information in here to describe the design feature of image 3";
purpleconeflower.save_userNote = [[NSUserDefaults standardUserDefaults] stringForKey:#"userNotes"];
My detail controller (PicDetailController.h) (works except for save_userNote)
//
// PicDetailController.h
//
// Created by John Lein Feb. 2017.
// Copyright (c) 2017 Lein Design Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PerennialDataYellow.h"
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
#import "SMPageControl.h"
#interface PicDetailController : UIViewController <NSFetchedResultsControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate, MFMailComposeViewControllerDelegate, UIScrollViewDelegate>
{
// NSString *save_userNote;
BOOL pageControlBeingUsed;
UIImage *blurrredImage;
BOOL didEdit;
IBOutlet UITextView *userNotes;
}
// allows me to use the plant label over again...
#property (nonatomic, strong) IBOutlet UILabel *plantnameLabel;
#property (nonatomic, strong) IBOutlet UILabel *plantnameLabel2;
...
#property (nonatomic, retain) IBOutlet UITextView *userNotes;
- (IBAction)handleSingleTap:(id)sender;
- (IBAction)emailButton:(id)sender;
- (IBAction)saveAction:(id)sender;
- (IBAction)clearNote:(id)sender;
#end
My detail controller (PicDetailController.m) works and it does save the save_userNotes but it saves the same note for every plant I view. So while it is successful in saving the note the user typed in, it is NOT unique for every record (plant)... I don't this something is being called back in the PerennialDataPurple.h file to make the connection...
// PicDetailController.m
// Created by John Lein Feb. 2017.
// Copyright (c) 2017 Lein Design Inc.. All rights reserved.
- (void)saveAction:(id)sender
{
NSString *valueToSave = userNotes.text;
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:#"userNotes"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSString *text = [[NSUserDefaults standardUserDefaults]objectForKey:#"userNotes"];
self.userNotes.text = text;
}
Notice in the first image - the note that was input by the user was saved... if I kill the app, force quit, and return it is saved... BUT NOT SAVED UNIQUE TO EACH PLANT... So when I view a second or third or forth image, the SAME USER NOTE APPEARS...
Any ideas how to make this work so EACH user note is unique to EACH plant...
I appreciate any help or insight...

Related

Pass values from a UIViewController to another

before the closing of my FlipsideViewController I have these values
shours
sminutes
sseconds
srecharge
change
from the declaration
int shours;
int sminutes;
int sseconds;
int srecharge;
bool change;
Now I want to pass these variables to another UIViewController (MainViewController) in these other variables
mhours
mminutes
mseconds
mrecharge
mchange
What's the simplest method to do this?
Create a custom object property on your MainViewController and set it on your FlipsideViewController or you can't do it for some reason: Create an object to hold these values and put it into NSUserDefaults and read on MainViewController.
I would simply create a "Model" class that holds those vars and pass the model class from one view controller to the next. Once it's linked in view1 & view2 during transition from view1 to view2, then it's automatically updated when transitioning back from view2 to view1. Use #property (assign) int shours so you have setters and getters created.
With this approach, using segues will work just fine. You don't need to use NSUserDefaults or NSNotificationCenter.
I would create a class to hold these values. Then pass this object between view controllers.
Something like this:
Interface file:
//
// MyObject.h
// SOObjectPassing
//
// Created by Wilson, LJ on 11/15/12.
// Copyright (c) 2012 Arkansas Children's Hospital. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface MyObject : NSObject {
int shours;
int sminutes;
int sseconds;
int srecharge;
bool change;
}
#property (nonatomic, assign) int shours;
#property (nonatomic, assign) int sminutes;
#property (nonatomic, assign) int sseconds;
#property (nonatomic, assign) int srecharge;
#property (nonatomic, assign) BOOL change;
-(id) initWithHours:(int)hours
minutes:(int)minutes
seconds:(int)seconds
recharge:(int)recharge
changed:(BOOL)changed;
#end
Implementation file:
//
// MyObject.m
// SOObjectPassing
//
// Created by Wilson, LJ on 11/15/12.
// Copyright (c) 2012 Arkansas Children's Hospital. All rights reserved.
//
#import "MyObject.h"
#implementation MyObject
#synthesize shours = _shours;
#synthesize sminutes = _sminutes;
#synthesize sseconds = _sseconds;
#synthesize srecharge = _srecharge;
#synthesize change = _change;
-(id) initWithHours:(int)hours
minutes:(int)minutes
seconds:(int)seconds
recharge:(int)recharge
changed:(BOOL)changed {
if ((self = [super init])) {
_shours = hours;
_sminutes = minutes;
_sseconds = seconds;
_srecharge = recharge;
_change = changed;
}
return self;
}
#end
And instantiate your object like this:
MyObject *myObject = [[MyObject alloc] initWithHours:2
minutes:3
seconds:4
recharge:1
changed:NO];
Then just pass that entire object to your other VC (s).
Here is a sample project illustrating this.

undeclared identifier on xcode

I just got to start developing for ios 6 on xcode.
But as a novice developer, i have come into a problem.
Following the guide in the book 'beginning ios5 development: exploring the ios sdk' on chapter 3, the 'Button fun' example.
I am having problems with the identifier 'statusText' which i have already declared in the .h code.
Here's my code so far, any help would be highly appreciated. thank you in advance.
my BIDViewController.h is like so
#import <UIKit/UIKit.h>
#interface BIDViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *
statusText;
- (IBAction)buttonPress:(UIButton *)sender;
#end`
and my BIDViewController.m is like so
#import "BIDViewController.h"
#interface BIDViewController ()
#end
#implementation BIDViewController
- (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.
}
- (IBAction)buttonPress:(UIButton *)sender {
NSString *title = [sender titleForState:<#(UIControlState)#>];
statusText.text = [NSString stringWithFormat:#"%# button pressed.", title];
}
#end
i have followed the book but can't seem to understand why this occurs, pls help.
Well, for starters, this should be only one line
#property (weak, nonatomic) IBOutlet UILabel *statusText;
Now, when you declare a property, you don't get a variable named like that unless you synthesize it like this:
#implementation Class
#synthesize propertyName;
#end
That's why statusText doesn't exist.
You have three options:
Synthesize statusText like that so you can use that ivar.
instead of accessing the var directly, access the property like this self.statusText.
XCode is creating it's own variable, it's probably named _statusText, access it like that to access the variable directly.
You can also use a combination of 2 and 3
I am using the same book and had that problem, too. I have learned to use an underscore in the .m file
- (IBAction)buttonPressed:(UIButton *)sender {
NSString *title = [sender titleForState:UIControlStateNormal];
**_statusText**.text = [NSString stringWithFormat:#"%# button pressed.", title];
}

Memory leak vs Zombie - iPhone

My iPhone app is either crashing due to to a zombie, or leaking memory.. I've narrowed it down to 3 lines of code and can reliably get one of the two things to happen by commenting/uncommenting the code. The bugs occur when navigation between a list of results (tableView) and a details page containing a map and a few labels, memory leak happens the first time I navigation from the map back to the list of results, the zombie occurs after maybe 5/6 times navigating to different results and back.
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#define METERS_PER_MILE 1609.344
#interface ResDetailsPageVC : UIViewController <MKMapViewDelegate, UIAlertViewDelegate> {
UISegmentedControl *mapTypeSwitcher;
MKMapView *mapView;
UILabel *nameLabel;
UIButton *addressLabel;
UILabel *telephoneLabel;
NSString *address;
}
#property (nonatomic, retain) IBOutlet UISegmentedControl *mapTypeSwitcher;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#property (nonatomic, retain) IBOutlet UIButton *addressLabel;
#property (nonatomic, retain) IBOutlet UILabel *telephoneLabel;
- (IBAction)segmentedControlIndexChanged;
- (IBAction)callButtonClick;
- (IBAction)addressClick;
- (void) callNumber;
#end
#synthesize mapView;
#synthesize mapTypeSwitcher;
#synthesize nameLabel, addressLabel, telephoneLabel;
- (void)dealloc {
// if these lines are commented out - memory leak
// if not - zombie?!
/*self.telephoneLabel = nil;
self.addressLabel = nil;
self.nameLabel = nil;*/
self.mapView = nil;
self.mapTypeSwitcher = nil;
[super dealloc];
}
Somewhere some other piece of code is using the same object whose address is stored in one of those three properties, but that other piece of code has not properly retained the object.
I recommend this to you:
- (void)dealloc {
[telephoneLabel release]; telephoneLabel = nil;
[addressLabel release]; addressLabel = nil;
....
[super dealloc];
}

Using AppDelegate for global readonly data

I have a project on iPhone with iOS4.
A instance variable of app delegate is a dictionary with global readonly data loaded from a plist when app starts.
CalculatorAppDelegate.h
#import <UIKit/UIKit.h>
#class MainViewController;
#interface CalculatorAppDelegate : NSObject <UIApplicationDelegate> {
NSDictionary *RGBSpacesDictionary;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain, readonly) NSDictionary *RGBSpacesDictionary;
#property (nonatomic, retain) IBOutlet MainViewController *mainViewController;
#end
CalculatorAppDelegate.m
#import "CalculatorAppDelegate.h"
#import "MainViewController.h"
#implementation CalculatorAppDelegate
#synthesize mainViewController=_mainViewController;
#synthesize RGBSpacesDictionary;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// load plist
NSString* plistPath1 = [[NSBundle mainBundle] pathForResource:#"RGBSpaces" ofType:#"plist"];
RGBSpacesDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath1];
etc.
}
Then in MainViewController i am able to successfully reading the dictionary in viewDidLoad
MainViewController.h
#class CalculatorAppDelegate;
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate> {
CalculatorAppDelegate *appDelegate;
}
#property (nonatomic, retain) CalculatorAppDelegate *appDelegate;
etc.
}
MainViewCOntroller.m
#import "CalculatorAppDelegate.h"
#implementation MainViewController
#synthesize appDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = [[UIApplication sharedApplication] delegate];
RGBSpacesCount = (int) [appDelegate.RGBSpacesDictionary count];
}
In viewDidLoad it is all OK, I can read my dictionary as appDelegate.REGSpaceDictionary.
The problem is with another method of MainVievController called when a button is pressed
- (IBAction) RGBSpaceButtonPressed {
NSLog(#"appDelegate.RGBSpacesDictionary %#", appDelegate.RGBSpacesDictionary);
etc.
}
At this time calling the dictionary (for example with a NSLog) return in a crash.
Can someone help me? Thank you.
In this line
RGBSpacesDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath1];
you are assigning an autoreleased object straight to the ivar so there is no guarantee how long it will stay around for. You should be assigning a non autoreleased object or going through the setter
// Going through the setter
self.RGBSpacesDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath1];
// OR
// Non assigning a non autoreleased object
RGBSpacesDictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath1];
To use the setter you would have to redeclare the property in an extension at the top of the app delegate's .m file like this
#interface CalculatorAppDelegate ()
#property (nonatomic, retain, readwrite) NSDictionary *RGBSpacesDictionary;
#end
...
The rest of your implementation
Try to retain the dictionary in app delegate. It must be deallocated at some point, because you get an autoreleased one and you didn't use the property to set it.
// here you must retain the dictionary
[[NSDictionary dictionaryWithContentsOfFile:plistPath1] retain];
Of course don't forget to release it later in dealloc.

Multiple View App shows Blank Screen in Simulator

I am developing a simple app that first shows a menu screen, and when a button is pressed, a game screen appears. I was able to develop the game screen without any issues, but when I changed the code to first display the menu, the simulator showed a blank screen.
I've read all the articles on connecting views with IB but I can't figure this out.
Any help would be appreciated.
This is my code:
// Pong_Multiple_ViewAppDelegate.h
// Pong Multiple View
//
// Created by Brett on 10-05-19.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import <UIKit/UIKit.h>
#class MenuViewController;
#interface Pong_Multiple_ViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MenuViewController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MenuViewController *navigationController;
#end
//
// Pong_Multiple_ViewAppDelegate.m
// Pong Multiple View
//
// Created by Brett on 10-05-19.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import "Pong_Multiple_ViewAppDelegate.h"
#import "MenuViewController.h"
#implementation Pong_Multiple_ViewAppDelegate
#synthesize window;
#synthesize navigationController;
- (void)application:(UIApplication *)application{
// Override point for customization after application launch
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
- (void)dealloc {
[navigationController release];
[window release];
[super dealloc];
}
#end
//
// MenuViewController.h
// Pong Multiple View
//
// Created by Brett on 10-05-19.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "GameViewController.h"
#interface MenuViewController : UIViewController {
GameViewController *gameViewController;
IBOutlet UIButton *gameButton;
}
#property(nonatomic, retain) GameViewController *gameViewController;
#property(nonatomic, retain) UIButton *gameButton;
-(IBAction)switchPage:(id)sender;
#end
//
// MenuViewController.m
// Pong Multiple View
//
// Created by Brett on 10-05-19.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "MenuViewController.h"
#import "GameViewController.h"
#implementation MenuViewController
#synthesize gameViewController;
#synthesize gameButton;
-(IBAction)switchPage:(id)sender{
if (self.gameViewController==nil) {
GameViewController *gameView = [[GameViewController alloc]initWithNibName:#"GameView" bundle:[NSBundle mainBundle]];
self.gameViewController= gameView;
[gameView release];
}
[self.navigationController pushViewController:self.gameViewController animated:YES];
}
....
#end
My code also includes classes: GameViewController.h, GameViewController.m, and nib files: MenuView.xib, and GameView.xib
Thanks,
B
- (void)application:(UIApplication *)application{
The method name must be -applicationDidFinishLaunching: (not -application:), otherwise UIKit can't find it and will ignore the initialization code.
In your Pong_Multiple_ViewAppDelegate.m, you try to add a view using
[window addSubview:[navigationController view]];
Are you sure that navigationController is instantiated anywhere? Either in code or using a nib?