iPhone:Store & Retrieve NSMutableArray object - objective-c

appDelegate.categoryData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
categoryStr, #"name",image ,#"image", nil];
[appDelegate.categories addObject:appDelegate.categoryData];
NSLog(#"Category Data:--->%#",appDelegate.categories);
I am successfully added object mutabledictionary into mutuablearray but I want to store that array and retrieve when application is launched so please give me idea to develop this functionality.
Thanks in advance.

//you can save array in NSUserDefaults like below
if ([[NSUserDefaults standardUserDefaults] valueForKey:#"detail"]==nil)
{
NSMutableDictionary *dic_detail = [NSMutableDictionary dictionaryWithObjectsAndKeys:
categoryStr, #"name",image ,#"image", nil];
NSMutableArray *ary_detail = [[NSMutableArray alloc] init];
[ary_detail addObject:dic_detail];
[[NSUserDefaults standardUserDefaults] setObject:ary_detail forKey:#"detail"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
//if you want read that array you can read like below in your app
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"detail"]];
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"applicationDidEnterBackground = %#",[[NSUserDefaults standardUserDefaults] objectForKey:#"detail"]);
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(#"applicationWillEnterForeground = %#",[[NSUserDefaults standardUserDefaults] objectForKey:#"detail"]);
}
in my log its printing like this
applicationDidEnterBackground = (
{
image = img1;
name = cat1;
}
applicationWillEnterForeground = (
{
image = img1;
name = cat1;
}

Perhaps something like this:
NSMutableArray * array = [NSMutableArray array];
appDelegate.categoryData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
categoryStr, #"name",
image ,#"image",
array, #"array", nil];

Something like:
On Application launch:
[[NSUserDefaults standardUserDefaults] registerDefaults:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSArray new], #"StoredArray", nil]];
In your class that "owns" control of the array:
- (void)setArray:(NSMutableArray *)array {
[[NSUserDefaults standardUserDefaults] setObject:array forKey:#"StoredArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (NSArray*)array {
return [[[NSUserDefaults standardUserDefaults] arrayForKey:#"StoredArray"] mutableCopy];
}
Hope this helps!

Related

App behaves differently when installed from IOS AppStore compared to iTunes AppStore

We have released a subscription based app that when the user downloads it, it starts as a trial app. When they purchase a in-app subscription they get the complete app.
The problem we are having is that if a user users the AppStore app from their phone to install the app they get the full version (Every user). and I know they haven't purchased anything. But if they download the app from iTunes, and use sync to install the app from through the computer unto their phone, the app starts as a trial and the options to buy the subscriptions are there.
I was told it had to do with the itunes indexing and a new version would fix it but a new version was approved today and we're having the same issue.
Any help is appreciated it.
Rico.
Edit: I have tested the same version that was sent to Apple using xCode simulator, an actual device, through adHoc development and opening the ipa using iTunes and they all work correctly. Not sure what else could be happening.
This method is called on launch:
// check in App Subscription status
-(void)checkInAppSubscriptionStatus{
NSString *accountType = FMAccountTypeTrial;
// get receipt
NSDictionary *receipt = [[FmIAPHelper sharedInstance] getStoreReceipt:NO];
// if receipt found
if([(NSNumber*)[receipt objectForKey:#"status"] integerValue] == 0){
// get exp date from receipt.
NSString *expDateStr = [[[receipt objectForKey:#"latest_receipt_info"] objectAtIndex:0] objectForKey:#"expires_date"];
NSString *productIdentifier = [[[receipt objectForKey:#"latest_receipt_info"] objectAtIndex:0] objectForKey:#"product_id"];
// set subscription type based on product identifier
NSString *subscriptionType = ([productIdentifier isEqualToString:FMInAppMonthSubscription])? FMSubscriptionTypeMonthly : FMSubscriptionTypeYearly;
expDateStr = [expDateStr stringByReplacingOccurrencesOfString:#"Etc/GMT" withString:#"GMT"];
NSDateFormatter *df = [FM_UIViewController mysqlTimeStampFormatter];
NSDate *expDate = [df dateFromString:expDateStr];
// expiration date has passed.
NSComparisonResult result = [expDate compare:[NSDate date]];
if(result == NSOrderedDescending || result == NSOrderedSame){ // date still valid
accountType = FMAccountTypePremium;
// save data for latest receipt
[[NSUserDefaults standardUserDefaults] setObject:subscriptionType forKey:FMSubscriptionTypeKey]; // monthly or yearly
[[NSUserDefaults standardUserDefaults] setValue:receipt forKey:FMSubscriptionLastReceiptKey]; // last receipt
[[NSUserDefaults standardUserDefaults] synchronize];
}
[[NSUserDefaults standardUserDefaults] setValue:expDate forKey:FMSubscriptionExpDateKey]; // expiration date
}
[[NSUserDefaults standardUserDefaults] setObject:accountType forKey:FMAccountTypeKey]; // premium or trial.
[[NSUserDefaults standardUserDefaults] synchronize]; //save
[self displayInitialContentView:#"InitialView"];
}
This is the getStoreReceipt method in the FMIAPHelper
// get the latest receipt
// this returns an NSDictionary of the app's store receipt, status=0 for good, -1 for bad
- (NSDictionary *) getStoreReceipt:(BOOL)sandbox {
NSArray *objects;
NSArray *keys;
NSDictionary *dictionary;
BOOL gotreceipt = false;
#try {
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) {
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
NSString *receiptString = [self base64forData:receiptData];
if (receiptString != nil) {
objects = [[NSArray alloc] initWithObjects:receiptString,FMiTunesConnectSharedSecret, nil];
keys = [[NSArray alloc] initWithObjects:#"receipt-data",#"password", nil];
dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
NSString *urlSting = #"https://buy.itunes.apple.com/verifyReceipt";
if (sandbox) urlSting = #"https://sandbox.itunes.apple.com/verifyReceipt";
NSString *postData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
dictionary = [self getJsonDictionaryWithPostFromUrlString:urlSting andDataString:postData];
if ([dictionary objectForKey:#"status"] != nil) {
if ([[dictionary objectForKey:#"status"] intValue] == 0) {
gotreceipt = true;
}
}
}
}
} #catch (NSException * e) {
gotreceipt = false;
}
if (!gotreceipt) {
objects = [[NSArray alloc] initWithObjects:#"-1", nil];
keys = [[NSArray alloc] initWithObjects:#"status", nil];
dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
}
return dictionary;
}
This method handles the display of trial information.
// account type
FMAccountType = [[NSUserDefaults standardUserDefaults] objectForKey:FMAccountTypeKey];
if([[[NSUserDefaults standardUserDefaults] objectForKey:FMSubscriptionExemptKey] isEqualToString:FMSubscriptionExempt]) FMAccountType = FMAccountTypePremium;
if(FMAccountType == nil){
FMAccountType = FMAccountTypeTrial;
}
The exempt part of the code is new on this version so I know that's not it.

Only first object of NSMutableArray is stored in NSUserDefaults

I am trying to store a queue of UILocalNotification to solve the limit problem. I used this approach and it does archive and unarchive my object but only the first one.
How do I archive all objects from my NSMutableArray?
Code
// init/unarchive queue
if (self.queue == nil)
{
// try loading stored array
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"LocalNotificationQueue"];
if (dataRepresentingSavedArray != nil) {
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil) {
self.queue = [[NSMutableArray alloc] initWithArray:oldSavedArray];
}
else
{
self.queue = [[NSMutableArray alloc] init];
}
}
else
{
self.queue = [[NSMutableArray alloc] init];
}
}
// add
[self.queue addObject:notif];
// store queue
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:self.queue] forKey:#"LocalNotificationQueue"];
If I add items 1,2,3. Restart and load. I have only 3.
Add 1,2,3. Restart and load. I have 3, 1, 2.
If it matters. This is a Phonegap/Cordova CDVPlugin.
After
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:self.queue] forKey:#"LocalNotificationQueue"];
You need to call
[[NSUserDefaults standardUserDefaults] synchronize]
To save the user defaults.
Try this, without the NSKeyedArchiver:
[[NSUserDefaults standardUserDefaults] setObject: self.queue] forKey:#"LocalNotificationQueue"];

Objective-C NSMutableArray removeObjectAtIndex: crashes

I have a view controller with a table view where you can delete the cells. I have another class which handles things called bookmarks, the class is called BookmarkHandler. There are methods where you can upload a bookmark, get the whole bookmark array and delete a bookmark. Here is the class as follows:
+ (NSMutableArray *)bookmarkCollection {
NSMutableArray *bookmarkCollection = [[NSUserDefaults standardUserDefaults] objectForKey: #"bookmarks"];
if (!bookmarkCollection) {
bookmarkCollection = [[NSMutableArray alloc] init];
}
return bookmarkCollection;
}
+ (void)deleteBookmark: (NSIndexPath *)indexPath {
NSMutableArray *bookmarkCollection = [[NSUserDefaults standardUserDefaults] objectForKey: #"bookmarks"];
[bookmarkCollection removeObjectAtIndex: indexPath.row];
[[NSUserDefaults standardUserDefaults] setObject:bookmarkCollection forKey: #"bookmarks"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (void)uploadBookmark:(NSDictionary *)singleBookmark {
NSMutableArray *bookmarkCollection = [[NSUserDefaults standardUserDefaults] objectForKey: #"bookmarks"];
if (!bookmarkCollection) {
bookmarkCollection = [[NSMutableArray alloc] init];
}
NSMutableDictionary *bookmark1 = [[NSMutableDictionary alloc] initWithDictionary: singleBookmark];
NSMutableDictionary *bookmark2 = [[NSMutableDictionary alloc] initWithDictionary: singleBookmark];
NSNumber *number1 = [[NSNumber alloc] initWithInt: 1];
NSNumber *number2 = [[NSNumber alloc] initWithInt: 2];
[bookmark1 setObject:number1 forKey: #"bookmarkTag"];
[bookmark2 setObject:number2 forKey: #"bookmarkTag"];
[bookmarkCollection addObject: bookmark1];
[bookmarkCollection addObject: bookmark2];
[[NSUserDefaults standardUserDefaults] setObject:bookmarkCollection forKey: #"bookmarks"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The bookmark collection which is a mutable array, is populated by dictionaries which have name and date objects/keys. These name and dates is what populates the table view cell title's in the other view controller. The number of cells in the table view is determined by the [[BookmarkHandler bookmarkCollection] count];
In the other view controller you can delete the table view cells, so what I do is I implement the delegate method:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[BookmarkHandler deleteBookmark: indexPath];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
}
So, when I delete a cell, I delete a bookmark from BookmarkHandler by calling the deleteBookmark: and delete the row from the table view. But sometimes there is a crash on this line:
[bookmarkCollection removeObjectAtIndex: indexPath.row];
But there is no crash log, and I have added an All Exceptions breakpoint.
Is there something I am doing wrong? Thanks for help...
The problem is here:
NSMutableArray *bookmarkCollection = [[NSUserDefaults standardUserDefaults] objectForKey: #"bookmarks"];
NSUserDefaults doesn't save a mutable array, it just saves it as NSArray.
So take the mutable copy of it:
NSMutableArray *bookmarkCollection = [[[NSUserDefaults standardUserDefaults] objectForKey: #"bookmarks"] mutableCopy];
You should check the indexPath.row to make sure it is NOT out of boundry. After this maybe you can find the reason.
if (indexPath.row>=0 && indexPath.row<bookmarkCollection.count) {
[bookmarkCollection removeObjectAtIndex: indexPath.row];
} else {
NSLog(#"indexPath.row is out of boundry of bookmarkCellection size: %d", bookmarkCollection.count);
}

How to Read String from NSUserDefaults

I have an object at the root of plist that stores objects and keys (one of which is input from a user textfield). I have no problem writing and creating structure; it's trying to read values that causing problem. Below code I used to write the data, can someone tell me how to read the string [val] and [myKey]?
thank you!
#define defaultValue #"Your Name"
#define myKey #"PersonName"
- (void)textFieldAction:(id)sender {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *val;
// Get the new value from the textfield
val = [myTextField stringValue];
if ([val isEqualToString:defaultValue]) {
[defaults removeObjectForKey:myKey];
} else {
// [defaults setObject:val forKey:myKey];
NSDictionary *my_dict = [NSDictionary dictionaryWithObjectsAndKeys:
#"Name", #"PersonName",
#"Email", #"PersonEmail",
#"Dept", #"PersonDept",
#"Job", #"PersonJob",
val, myKey,
#"Status", #"PersonStatus",
nil];
[defaults setObject: my_dict forKey: #"Person"];
[[NSUserDefaults standardUserDefaults] registerDefaults:my_dict];
I would like to automatically populate the textfield with the [val], for [myKey], if the user has the info already in the plist. Here's the code I'm trying to use for that:
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSUserDefaults *defaults = [[NSUserDefaults standardUserDefaults] objectForKey:myKey];
NSString *val = [defaults stringForKey:myKey];
if (val == nil) val = defaultValue;
[myTextField setStringValue:val];
You can write the value into NSUserDefault like the following:
[[NSUserDefaults standardUserDefaults] setValue:[myTextField stringValue] forKey:#"Person"];
And read it later like the following:
[myTextField setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:#"Person"];
So you can simplify your code into:
- (void)textFieldAction:(id)sender {
[[NSUserDefaults standardUserDefaults] setValue:[myTextField stringValue] forKey:#"Person"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
You can set a default value with the registerDefaults:. And when you can retrieve that value simply by calling:
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
// ...
[[NSUserDefaults standardUserDefaults] registerDefaults:#{#"Person", defaultValue}]
NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:#"Person"];
[myTextField setStringValue:value];
// ...
}
If I understand correctly, you should be able to do what you need by simply doing:
NSString * val = [[NSUserDefaults standardUserDefaults] objectForKey: myKey];
[textfield setText: val];
NSUserDefaults Reference Page
myTextField.text = [[NSUSerDefaults standardUserDefaults] objectForKey:myKey];

NSMutableArray won't add NSDictionary

I updated to cocos2d from 0.99.4 to 0.99.5. While it was on the older version I had the high score list working and I was able to add the NSDictionary to NSMutableArray with no problems.
Now that I've updated it won't add the NSDictionary variable scoreDetails to my NSMutableArray scoreList. Here's my code:
StatsManager.h
#interface StatsManager : NSObject {
NSMutableArray *scoreList;
NSUserDefaults *saveHighScore;
NSMutableArray *printableScoreList;
//NSMutableArray *scoreListTestOne;
float highScoreHelloWorld;
}
StatsManager.m
-(void)setHighScore:(float)highScore nameStrings:(NSString*)nameString {
NSNumber *newHighScore = [NSNumber numberWithFloat:highScore];
NSLog(#"%# highScore", newHighScore);
NSDictionary *scoreDetails = [NSDictionary dictionaryWithObjectsAndKeys:nameString, #"name", newHighScore, #"score", nil];
NSLog(#"%#", scoreDetails);
//NSMutableArray *testTwo = [[NSMutableArray alloc] init];
[scoreList addObject:scoreDetails];
NSLog(#"scoreList %#", scoreList);
//[scoreListTestOne addObject:scoreDetails];
//NSLog(#"scoreListTestOne %#", scoreListTestOne);
//sort
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"score" ascending:NO];
[scoreList sortUsingDescriptors:[NSArray arrayWithObject:sort]];
printableScoreList = scoreList;
NSLog(#"printableScoreList %#", printableScoreList);
//NSLog(#"scoreListTestOne %#", scoreListTestOne);
}
The line in question is
[scoreList addObject:scoreDetails];
I created a local NSMutableArray variable in the setHighScore function and tried adding the scoreDetails to that and it worked. but why doesn't it work like I've coded it above anymore?
I alloc init my scoreList here:
#implementation StatsManager
static StatsManager *_sharedStatsManager = nil;
-(id)init {
scoreList = [[NSMutableArray alloc] init];
//playerNames = [[NSMutableArray alloc] init];
//playerScores = [[NSMutableArray alloc] init];
printableScoreList = [[NSMutableArray alloc] init];
//listOfScoresTest = [[NSMutableDictionary alloc] initWithCapacity:5];
/*if ([scoreList count] == 0) {
for (int i = 0; i < 5; i++) {
[scoreList addObject:[NSNumber numberWithFloat:0.00]];
}
}*/
return [super init];
}
I should also mention that I created a new projectB and transferred my files/images from my old projectA to the new one because the old one wouldn't compile anymore because of some duplicate error. But i "cleaned all targets" again and it worked but that also has the same problem as my new projectB
Do you initialize scoreList ivar in init or so forth?
- (id)init
{
/* snip */
scoreList = [[NSMutableArray alloc] init];
return self;
}
- (void)dealloc
{
[scoreList release];
[super dealloc];
}
Ok Georg I reconsidered your suggestion about overwriting it later.
and it had something to do with my NSUserdefaults. I commented them out and now it add's the objects to my NSMutableArray. I'm pretty new to NSUserdefaults so I don't know exactly how to use it atm lol
-(void)save
{
//make another array to save the scores.
saveHighScore = [NSUserDefaults standardUserDefaults];
//[saveHighScore setObject:scoreListNew forKey:#"DodgerAppBeta"];
[saveHighScore synchronize];
//[[NSUserDefaults standardUserDefaults] setObject:scoreListTestOne forKey:#"DodgerBeta"];
//[[NSUserDefaults standardUserDefaults] synchronize];
}
-(void)load
{
saveHighScore = [NSUserDefaults standardUserDefaults];
//scoreListNew = [[saveHighScore objectForKey:#"DodgerAppBeta"] mutableCopy];
printableScoreList = [[saveHighScore objectForKey:#"DodgerAppBeta"] mutableCopy];
//NSLog(#"scoreListTestOne %#", scoreListTestOne);
//[printableScoreList addObject:[[NSUserDefaults standardUserDefaults] objectForKey:#"Dodger"]];
NSLog(#"PSL %#", printableScoreList);
}