Creating Plist iOS - ios

I'm trying to make a restaurant queue app whose first page will be with three buttons, one of them being 'New Reservation'. When clicked on it, it opens a new view that takes in the customers name,phone number and total number of people, the waiter will enter the estimated time for their order and press enter which will save all these values in a plist. I'm referring to youtube videos to create plist, but I have a view controller class in which I initialize the plist and also a NewReservation class that controls the saving data. According to the video I create the plist in viewDidLoad method and also copy few lines of it in the IBAction of the button "enter details". I'm jumbled up and can't access the values in my NewReservation class, please clarify.
Thank you.
ViewController.h
#import <UIKit/UIKit.h>
#class NewReservation;
#interface ViewController : UIViewController
#property (nonatomic , strong) NewReservation *Res;
#end
ViewController.m
#import "ViewController.h"
#import "NewReservation.h"
#interface ViewController ()
#end
#implementation ViewController{
NSMutableArray *phoneNumbers , *name , *noOfPeople , *estTime;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.Res = [[NewReservation alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Property List.plist"];
if(![[NSFileManager defaultManager] fileExistsAtPath:plistPath]){
plistPath = [[NSBundle mainBundle] pathForResource:#"Property List" ofType:#"plist"];
}
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSDictionary *temp = (NSDictionary *) [NSPropertyListSerialization propertyListWithData:plistXML options:NSPropertyListMutableContainersAndLeaves format:&format error:&errorDesc];
if(!temp){
NSLog(#"Error Reading plist: %# , format: %lu",errorDesc , format);
}
name = [NSMutableArray arrayWithArray:[temp objectForKey:#"name"]];
phoneNumbers = [NSMutableArray arrayWithArray:[temp objectForKey:#"phoneNumbers"]];
noOfPeople = [NSMutableArray arrayWithArray:[temp objectForKey:#"noOfPeople"]];
estTime = [NSMutableArray arrayWithArray:[temp objectForKey:#"estTime"]];
//Confused how to go further
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
NewReservation.h
#import <UIKit/UIKit.h>
#interface NewReservation : UIViewController{
}
#property (weak, nonatomic) IBOutlet UITextField *name;
#property (weak, nonatomic) IBOutlet UITextField *phoneNumber;
#property (weak, nonatomic) IBOutlet UITextField *noOfPeople;
#property (weak, nonatomic) IBOutlet UITextField *estTime;
- (IBAction)nameReturn:(id)sender;
- (IBAction)enterDetails:(id)sender;
#end
NewReservation.m
#import "NewReservation.h"
#implementation NewReservation
- (IBAction)enterDetails:(id)sender{
if([self.name.text isEqualToString:#""] || [self.phoneNumber.text isEqualToString:#""] || [self.noOfPeople.text isEqualToString:#""] || [self.estTime.text isEqualToString:#""]) {
UIAlertView *error = [[UIAlertView alloc] initWithTitle:#"Oops" message:#"You must complete all fields!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[error show];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Property List.plist"];
//Cant continue here cause its confusing me, i need to add the values and update the list everytime a new 'name,noOfPersons,phoneNumber,estTime
//is entered.
}
#end

An instance variable is unique to a class. By default, only the class and subclasses can access it. Therefore, as a fundamental principal of object-oriented programming, instance variables (ivars) are private—they are encapsulated by the class.
By contrast, a property is a public value that may or may not correspond to an instance variable. If you want to make an ivar public, you'd probably make a corresponding property. But at the same time, instance variables that you wish to keep private do not have corresponding properties, and so they cannot be accessed from outside of the class. You can also have a calculated property that does not correspond to an ivar…
Without a property, ivars can be kept hidden. In fact, unless an ivar is declared in a public header it is difficult to even determine that such an ivar exists.
Your child class have a properties that does not correspond to an ivar
To access the ivar with properties the ivar need to be synthesise properties in from child class.
#implementation NewReservation
#synthesize phoneNumbers, name, noOfPeople, estTime;
// ****
#end

Related

How can I ensure value is in the custom class property at the NSMutableArray?

I create the custom class name with FileModel.
FileModel.h
#import <Foundation/Foundation.h>
#interface FileModel : NSObject
#property (nonatomic, copy) NSString *fileName;
#property (nonatomic, copy) NSString *fileType;
#property (nonatomic, strong) NSDate *editDate;
#property (nonatomic, assign) NSInteger fileSize;
#end
I want to compare the particular string with the fileName.
I create the sample like below .m
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *fileSampleName = [[NSArray alloc] initWithObjects:#"apple.png",#"banana.png",#"cherry.png",#"durian.png",#"grape.png",#"avocado.png", nil];
NSMutableArray *fileData = [NSMutableArray new];
FileModel *fileModel = nil;
for( NSInteger i = 0 ; i < fileSampleName.count ; i++){
fileModel = [FileModel new];
fileModel.fileName = [fileSampleName objectAtIndex:i];
fileModel.fileType = #"photo";
fileModel.fileSize = 0;
fileModel.editDate = [NSDate new];
[fileData addObject:fileModel];
}
// fileData's fileName containsObject #"grape" or not?
}
NSArray has containsObject method.
But How can I check the #"grape" is containsObject using fileData at the custom class property filename?
I known using for loop compare one by one.
Did they have other method to check like containsObject?
--- edit---
I try to using indexOfObjectPassingTest method , But the result always is 1.
BOOL result = [fileData indexOfObjectPassingTest:^ BOOL (id tr,NSUInteger index, BOOL *te){
FileModel *fileModel = (FileModel*)tr;
if([#"orange" isEqualToString: fileModel.fileName]){
*te = YES;
return YES;
}else{
return NO;
}}];
NSLog(#"result:%#",#(result)); // it always return 1
Why? thank you very much.
Take a look that NSArray class reference in Xcode. One method you could use is indexOfObjectPassingTest. There are number of related methods depending on your needs. All take a block that's used to test objects to see if they meet whatever criteria you want. In your case you'd test the fileName string.
So you'd pass in a closure that compared the fileName property of each object to your desired filename.

Can't write NSDictionary parameters into custom Object

I was stuck on writing NSDictionary into Object process, I am sure that problem is simple as I imagine but would be great to get assistant. Here is my code:
my custom object:
#interface User : NSObject
#property (nonatomic, retain) NSString *cId;
#property (nonatomic, retain) NSString *firstName;
#property (nonatomic, retain) NSString *lastName;
....
-(instancetype) initWithParameters:(NSDictionary*) parameters;
#end
#import "User.h"
#implementation User
-(instancetype) initWithParameters:(NSDictionary*) parameters
{
self = [super init];
if (self) {
[self setParameters:parameters];
}
return self;
}
- (void) setParameters:(NSDictionary*) parameters{
_cId = parameters[#"cId"];
_firstName = parameters[#"first_name"];
_lastName = parameters[#"last_name"];
....
}
and writing process:
id userObjects = [resultData objectForKey:#"data"];
NSMutableArray* mUsers = [[NSMutableArray alloc] init];
for (NSDictionary* userParameters in userObjects) {
User *user = [[User alloc] initWithParameters:userParameters];
[mUsers addObject:user];
}
userObjects - NSArray got from JSON object from server data.
The problem is : nothing happening and user object still empty after initialization, then I have tried - setValuesForKeysWithDictionary after I called variables same as keys in dictionary and nothing changed.
after adding in mUsers:
Could anybody tell me what I am doing wrong? Thank you!
I believe you think those objects are uninitialized because you are seeing 0 key/value pairs next to each User object.
Your code looks good and I think things will change once you implement [NSObject description] (or [NSObject debugDescription]) like this:
- (NSString *)description
{
return [NSString stringWithFormat:#"cId=%#, firstName=%#, lastName=%#",
_cId, _firstName, _lastName];
}

Unable to store a NSMutableArray(each instance of array contains a custom object) in NSUserDefaults

It's a custom class:
#import <Foundation/Foundation.h>
#interface timeTable : NSObject
#property (nonatomic) int ID;
#property (nonatomic) NSString * type;
#property (nonatomic) NSString * time;
#property (nonatomic) NSString * busno;
#property (nonatomic) NSString * stops;
// nothing is done in it's .m file not even synthesise
// thats an other class
#import <Foundation/Foundation.h>
#import "timeTable.h"
#interface refreshDatabase : NSObject
#property (strong, nonatomic) NSMutableArray * arrayTimeTable;
#property (strong, nonatomic) timeTable * objectTimeTable;
// in it's .m file i am downloading a JSON formatted array using a
service then i am saving it to NsMutbaleArray
// downloading a json array which contains a rows of data
NSError * error;
NSArray * jsonArray = [NSJSONSerialization JSONObjectWithData:
[safeString dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingAllowFragments error:&error];
NSLog(#"json Array %#", jsonArray);
// for getting an instance of array
NSDictionary * jsonElement;
for (int i=0; i<jsonArray.count ; i++)
{ // each row will be saved in an object of timetable class then that
// object will be saved to nsmutablearray
jsonElement = [jsonArray objectAtIndex:i];
objectTimeTable = [[timeTable alloc]init];
objectTimeTable.ID = [[jsonElement objectForKey:#"id"]intValue];
objectTimeTable.type = [jsonElement objectForKey:#"type"];
objectTimeTable.time = [jsonElement objectForKey:#"time"];
objectTimeTable.busno = [jsonElement objectForKey:#"busno"];
objectTimeTable.stops = [jsonElement objectForKey:#"stops"];
// adding an instance from JSON Array to our NSmutablearray
[arrayTimeTable addObject:objectTimeTable];
}//end of json Array FOR loop
// our array containnig all the objects will be saved using
//NSUserDefualts
// userDefaults is an object of NSUserDefaults
if(userDefaults)
{ // its not saving it to userdefaults
[userDefaults setObject:arrayToStore forKey:#"ArrayOfTimeTables"];
[userDefaults synchronize];
}
// retrieving the saved array from NSUSerDefaults and printing it
// using slog
timeTable *objPrint = [[timeTable alloc]init];
NSMutableArray *arrayLoader = [userDefaults arrayForKey:#"ArrayOfTimeTables"];
for (int i=0; i<arrayLoader.count ; i++)
{
objPrint = [arrayLoader objectAtIndex:i];
NSLog(#"outSide Printing For LOOP After Loading of tim # %d times havind id =%d type = %# time = %# busno = %# stops = %#",i,objPrint.ID,objPrint.type,objPrint.time,objPrint.busno,objPrint.stops);
}
Thanx a lot in helping me in advance.
Please tell me how to save that array which contains object of timetable class into nsUseDefaults and then how to load it back.
Please help me. I read a lot of similar question and answers, but don't know how to make them work for me.
Use NScoding to encode each of your custom object then add that custom object into an array then encode other and then add it to the array then save that array into NSUserDefaults
encoding and decoding of upper given question
is
the custom class .h file
#import <Foundation/Foundation.h>
#interface timeTable : NSObject<NSCoding>
#property (nonatomic) NSString * ID;
#property (nonatomic) NSString * type;
#property (nonatomic) NSString * time;
#property (nonatomic) NSString * busno;
#property (nonatomic) NSString * stops;
the custom class .m file
#import "timeTable.h"
#implementation timeTable
#synthesize ID;
#synthesize type;
#synthesize time;
#synthesize busno;
#synthesize stops;
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.ID forKey:#"ID"];
[aCoder encodeObject:self.type forKey:#"type"];
[aCoder encodeObject:self.time forKey:#"time"];
[aCoder encodeObject:self.busno forKey:#"busno"];
[aCoder encodeObject:self.stops forKey:#"stops"];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if((self = [super init])) {
//decode properties, other class vars
self.ID = [aDecoder decodeObjectForKey:#"ID"];
self.type = [aDecoder decodeObjectForKey:#"type"];
self.time = [aDecoder decodeObjectForKey:#"time"];
self.busno = [aDecoder decodeObjectForKey:#"busno"];
self.stops = [aDecoder decodeObjectForKey:#"stops"];
}
return self;
}
#end
where you encode each custom object one by one and adding it to the array then save that NSMutableArray or NSArray
into NSUserDefaults
encoding a custom object then adding it to array and saving it into user defaults
// encoding a custom object before saving it to array
NSData *encodeTimeTableObj = [NSKeyedArchiver
archivedDataWithRootObject:objectTimeTable];
addObject:encodeTimeTableObj];
//saving it to user Defaults
if(userDefaults)
{
[userDefaults setObject:arrayTimeTable
forKey:#"ArrayOfTimeTables"];
[userDefaults synchronize];
NSLog(#"saving to usedefaults");
}
retriving an array either mutable or non mutable then decoding each of its object
NSMutableArray *arrayLoader = [userDefaults
objectForKey:#"ArrayOfTimeTables"];
NSData * decode = [arrayLoader objectAtIndex:0];
  // in case of upper given custom class Time Table
timeTable *objPrint = [NSKeyedUnarchiver unarchiveObjectWithData:decode];
Use NSArray to get array from NSUSerDefaults as NSUSerDefaults return immuttable array.
If you need NSMutableArray, then convert this NSArray to NSMutableArray.
// retrieving the saved array from NSUSerDefaults and printing it
// using slog
timeTable *objPrint = [[timeTable alloc]init];
NSArray *arrayLoader = [userDefaults arrayForKey:#"ArrayOfTimeTables"];
for (int i=0; i

Address book data persistence?

(storyboard image)
http://i.stack.imgur.com/DUZ12.png
Have 3 text fields where user inputs data and saves it. Upon opening the application, if there is any save data, the previous input is displayed within the text fields. Problem is, there is only one set of data, while it needs to be an array with multiple people's information. I would like to instead create a navigation controller with cells with names and upon clicking on them it displays the correlating contact info.
viewcontroller.h
#interface ArchiveViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *name;
#property (strong, nonatomic) IBOutlet UITextField *address;
#property (strong, nonatomic) IBOutlet UITextField *phone;
#property (strong, nonatomic) NSString *dataFilePath;
- (IBAction)saveData:(id)sender;
#end
viewcontroller.m
#interface ArchiveViewController ()
#end
#implementation ArchiveViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSFileManager *filemgr;
NSString *docsDir;
NSArray *dirPaths;
filemgr = [NSFileManager defaultManager];
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the data file
_dataFilePath = [[NSString alloc] initWithString: [docsDir
stringByAppendingPathComponent: #"data.archive"]];
// Check if the file already exists
if ([filemgr fileExistsAtPath: _dataFilePath])
{
NSMutableArray *dataArray;
dataArray = [NSKeyedUnarchiver
unarchiveObjectWithFile: _dataFilePath];
_name.text = dataArray[0];
_address.text = dataArray[1];
_phone.text = dataArray[2];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)saveData:(id)sender {
NSMutableArray *contactArray;
contactArray = [[NSMutableArray alloc] init];
[contactArray addObject:self.name.text];
[contactArray addObject:self.address.text];
[contactArray addObject:self.phone.text];
[NSKeyedArchiver archiveRootObject:
contactArray toFile:_dataFilePath];
}
#end
Thank you for your time.
Instead of having an array with 3 elements of text in it and using NSKeyedArchiver, have an array with dictionaries in it and save it with writeToFile:atomically:. This will use the array as a list of 'entries' rather than a list of fields and will save the data in a plist instead of a binary file.
Now, when you read in the array you can display a table view of the entries (just showing the name for example) and then when you show the archive view you would pass the controller the a appropriate dictionary.
For saving, it would be good to use delegation to pass the edit back to the master controller. But it could also be done directly (requires more knowledge in the detail controller) or by notification.

iPhone NSMutableArray and NSKeyedUnarchiver unarchiveObjectWithFile release oddity

I archive an array (NSMutableArray) of custom objects that implement the .
Once i load it froma file to a retaining property
#property (nonatomic, retain) NSMutableArray *buddies;
the release count of the object is 2 (correct, it's 1of autorelease + 1 of retain of the property) but then noone releases it and the retain count becames 1, so when i release it i get
-[__NSArrayM retainCount]: message sent to deallocated instance
(i think because the 1 retain count is the autorelease)
Here's the full code:
BuddieListViewController.h
#import <UIKit/UIKit.h>
#import "Buddie.h"
#interface BuddieListViewController : UITableViewController {
IBOutlet NSMutableArray *buddies;
[...]
}
[...]
#property (nonatomic, retain) NSMutableArray *buddies;
[...]
#end
BuddieListViewController.m
#import "BuddieListViewController.h"
#import "Buddie.h"
#import "PreviewViewController.h"
#implementation BuddieListViewController
#synthesize buddies;
[...]
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
[self loadFromDisk];
}
return self;
}
- (void)loadFromDisk {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *appFile = [documentsPath stringByAppendingPathComponent:#"BuddieArchive.ark"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:appFile]) {
self.buddies = [NSKeyedUnarchiver unarchiveObjectWithFile:appFile];
NSLog(#"1- buddies retain count %d (should be 2, 1 + 1autorelease)", [buddies retainCount]);
} else {
self.buddies = [NSMutableArray arrayWithCapacity:1];
}
}
[...]
- (IBAction)cancelledBuddie:(NSNotification *)notification
{
[editingBuddie release];
NSLog(#"2- buddies retain count %d (should be 2, 1 + 1autorelease)", [buddies retainCount]);
[buddies release];
[self loadFromDisk];
[self.tableView reloadData];
}
Has anyone some idea of why this happens?
I can't say it better than this:
The number returned by retainCount is
useless.
Don't rely on it for anything. Use the Leaks tool in Instruments to determine if you're leaking objects.
If you're crashing, it's most likely that you have a zombie. See this video to find out how to use Instruments to find zombies.
If you need to nullify the array, use the property accessor to set it to nil:
self.buddies = nil;
The synthesized implementation takes care of the memory management issues. Try to avoid sending -retain/-release messages directly to instance variables wherever possible and instead allow the property accessors to take care of things for you. It'll save you a lot of trouble.
Rather than releasing buddies why not just do a [self.buddies removeAllObjects] at the beginning of loadFromDisk.

Resources