Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm building an app for tap counting (for example: people going into the room).
The main goal is to be able to have multiple counters (for example: counter for main room, counter for white room, counter for green room etc.).
The app consists of:
A list of counters - CounterListTableViewController, with function
is to create new items (counters) in the list
A counter page - RowCounterViewController
I am stuck at the moment at: Saving count number of counters with reference to item in the TableViewController.
Possible solutions:
Save all count numbers into an array - I don’t know how yet (a complete beginner).
Save all count numbers in NSUserDefaults with its index, as suggested by KudoCC in answers bellow.
Thank you!
Last edit:
#import "RowCounterViewController.h"
#interface RowCounterViewController ()
#end
#implementation RowCounterViewController
-(IBAction)plus {
counter=counter + 1;
count.text = [NSString stringWithFormat:#"%i",counter];
}
-(IBAction)minus {
counter=counter - 1;
count.text = [NSString stringWithFormat:#"%i",counter];
}
-(IBAction)reset {
counter=0;
count.text = [NSString stringWithFormat:#"%i",counter];
}
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveCount)
name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveCount)
name:UIApplicationWillTerminateNotification object:nil];
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:#"saveCount"] ;
NSUInteger count = [dict objectForKey:#(itemIndex)] ;
//NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//NSString *countString = [userDefaults objectForKey:#"saveCount"];
//NSLog(#"Your Count: %#",count);
//checking if data in user defaults is not empty
//if(countString.length>0)
//{
// count.text = [NSString stringWithFormat:#"%i",counter];
// counter = [countString intValue];
//}
//else
//{
// //for first time
// counter = 0;
// count.text = #"0";
//}
//counter=0;
//count.text = #"0";
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)saveCount {
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:#"saveCount"] ;
NSMutableDictionary *mDict = [dict mutableCopy] ;
[mDict setObject:#(count) forKey:#(itemIndex)] ;
[[NSUserDefaults standardUserDefaults] setObject:mDict forKey:#"saveCount"] ;
[[NSUserDefaults standardUserDefaults] synchronize] ;
}
//- (void)dealloc {
// [self saveCount] ;
//}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before
navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
You can call [self saveCount] in dealloc method or viewWillDisappear:.
- (void)dealloc {
[self saveCount] ;
}
or:
- (void)viewWillDisappear:(BOOL)animated {
[self saveCount] ;
}
Update:
It seems that you want to keep the count for every item in your list. In order to achieve this, you must save the all the count in NSUserDefaults with its index, I recommend you to save NSDictionary which use index as its key and count as its value. So when you push into the RowCounterViewController, you should tell the index number of the item, so you can get its count in NSUserDefaults. When you leave the view controller, save its count to the index.
The code below is used to fetch the count for itemIndex, you should tell RowCounterViewController the item index before push or present it.
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:#"saveCount"] ;
NSUInteger count = [[dict objectForKey:#(itemIndex)] unsignedIntegerValue] ;
The code below is used to save the count for itemIndex.
-(void)saveCount {
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:#"saveCount"] ;
NSMutableDictionary *mDict = [dict mutableCopy] ;
[mDict setObject:#(count) forKey:#(itemIndex)] ;
[[NSUserDefaults standardUserDefaults] setObject:mDict forKey:#"saveCount"] ;
[[NSUserDefaults standardUserDefaults] synchronize] ;
}
and next bit of code in the list view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetail"]) {
// you can fetch the selected index path in this way.
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RowCounterViewController *vc = (RowCounterViewController*)[segue destinationViewController];
// the currentIndex is the itemIndex I mentioned above.
vc.currentIndex = indexPath.row;
}
}
if you have more than one counter, you need an array to store all counter , and use UITableViewDelegate and UITableViewDatasource to present counters for rows in the tableview.
save the array to a file with this method
[array writeToFile:arrayFileName atomically:YES];
or you can use anything you can come up with to store it in
dealloc or viewWillDisappear
if you want to communicate between your tableview and RowCounterViewController, say RowCounterViewController passing the counter number back to tableview and present it in the related item, you can use delegate or notification.
that's something you need to learn in the future.
you can find some demo about it.
good luck.
Related
I have created a array in my controller. Based on that JSON array my cards[tinderswipecards/cwRichard] are created . Now I want if I remove a card I want to get the data of card Shown to display somewhere in my viewController something like this
My cards coming from DraggableBackgroundView Class and i m implementing this in my own viewController
_peopleNearBypeopleList = [NSMutableArray new];
[dataArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
{
PeopleNearByIndividualModel * model = [PeopleNearByIndividualModel new];
NSDictionary *dicData = obj;
model.senderId = [[dicData objectForKey:USER_ID] integerValue];
model.displayName = [[dicData objectForKey:DISPLAY_NAME] uppercaseString];
model.userImage = [dicData objectForKey:#"image"];
[self.peopleNearBypeopleList addObject:model];
NSLog(#"%#",_peopleNearBypeopleList);
if (idx == [dataArray count] - 1) {
[self createInvitationViews];
}
and the strings to be created like
int i;
for (i = 0; i < [_peopleNearBypeopleList count]; i++) {
PeopleNearByIndividualModel * model = [_peopleNearBypeopleList objectAtIndex:i];
NSString *nameString = #"ARE YOU SURE YOU WANT TO INVITE ";
nameString = [nameString stringByAppendingString:model.displayName];
NSLog(#"%#", nameString);
_textView.textColor = [UIColor whiteColor];
_textView.font = [UIFont fontWithName:#"Roboto-Regular" size:17.0f];
_textView.text = nameString;
}
again and it is calling the first Object.how can i acheive this
this is my draggableViewBackground Class
//%%% loads all the cards and puts the first x in the "loaded cards" array
-(void)loadCards:(NSArray*)array
{
exampleCardLabels = array;
if([exampleCardLabels count] > 0) {
NSInteger numLoadedCardsCap =(([exampleCardLabels count] > MAX_BUFFER_SIZE)?MAX_BUFFER_SIZE:[exampleCardLabels count]);
//%%% if the buffer size is greater than the data size, there will be an array error, so this makes sure that doesn't happen
//%%% loops through the exampleCardsLabels array to create a card for each label. This should be customized by removing "exampleCardLabels" with your own array of data
for (int i = 0; i<[exampleCardLabels count]; i++) {
MG_DraggableVIew* newCard = [self createDraggableViewWithDataAtIndex:i];
[allCards addObject:newCard];
if (i<numLoadedCardsCap) {
//%%% adds a small number of cards to be loaded
[loadedCards addObject:newCard];
}
}
//%%% displays the small number of loaded cards dictated by MAX_BUFFER_SIZE so that not all the cards
// are showing at once and clogging a ton of data
for (int i = 0; i<[loadedCards count]; i++) {
if (i>0) {
[self insertSubview:[loadedCards objectAtIndex:i] belowSubview: [loadedCards objectAtIndex:i-1]];
} else {
[self addSubview:[loadedCards objectAtIndex:i]];
}
cardsLoadedIndex++; //%%% we loaded a card into loaded cards, so we have to increment
}
}
// }
}
#warning include own action here!
//%%% action called when the card goes to the left.
// This should be customized with your own action
-(void)cardSwipedLeft:(UIView *)card;
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
#warning include own action here!
//%%% action called when the card goes to the right.
// This should be customized with your own action
-(void)cardSwipedRight:(UIView *)card
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
//%%% when you hit the right button, this is called and substitutes the swipe
-(void)swipeRight
{
MG_DraggableVIew *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeRight;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView rightClickAction];
}
//%%% when you hit the left button, this is called and substitutes the swipe
-(void)swipeLeft
{
MG_DraggableVIew *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeLeft;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView leftClickAction];
}
you can post a NSNotification inside -(void)cardSwipedLeft:(UIView *)card & -(void)cardSwipedRight:(UIView *)card method in DraggableViewBackground.
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:index] forKey:#"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:self userInfo:userInfo];
Here index is your card index. To set the index, you can declare a int property named index. Set initial value value of index like index=0; in initwithframe method.
then, increase the value of index when you swipe a card.
set index++; inside -(void)cardSwipedLeft:(UIView *)card & -(void)cardSwipedRight:(UIView *)card method in DraggableViewBackground.
Listen for this notification in your view controller. To achieve that add in the view controller's method in viewDidLoad by this line:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
implement this selector method in your viewcontroller-
- (void) receiveTestNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"TestNotification"]){
NSLog (#"Successfully received the test notification!");
NSDictionary *userInfo = notification.userInfo;
int myObject = [[userInfo objectForKey:#"someKey"]integerValue];
NSLog(#"index: %d", myObject);
}
}
on receiveTestNotification method you get card index. then you can get your data from your array by index.
In my opinion, it will be better for you if you maintain a dictionary for cards and their data.
You can create a dictionary with keys as card ids/card numbers and values as their data (description.)
So whenever you are removing card, simply fetch its data from dictionary.
Lets say cardsDictionary is your dictionary like this :
cardsDictionary = #{#"card1_id":#"card1_data"......#"cardn_id":#"cardn_data"};
Then on removing a card you can do like this:
card_data = cardsDictionary[#"card_id"];
I have a program where a user enter strings into an NSMutableArray (myArray) via a Text Field. This array is passed into the next view controller where there is a label (myLabel) and two buttons. Printed to the label is a random string from myArray. ButtonA displays a different random string from the array when pressed and ButtonB removes the current string that is printed to the label and then displays a random string from the array to the label.
This is my current solution:
- (void)viewDidLoad {
self.myLabel.text = [self.myArray objectAtIndex:arc4random() % [myArray count]];
-(IBAction)ButtonA:(id)sender {
self.myLabel.text = [self.myArray objectAtIndex:arc4random() % [myArray count]];
}
-(IBAction)ButtonB:(id)sender {
NSInteger index = [myArray indexOfObject: //what goes here?];
[self.myArray removeObjectAtIndex:index];
self.myLabel.text = [self.myArray objectAtIndex:arc4random() % [myArray count]];
}
Is there a way to get the index of the random string displayed and then remove it from the array? I want this to continue doing this until all items from the array have been removed. Thank you
The // what goes here? should simply be self.myLabel.text.
Though it might be better to add an instance variable that saves off the last random index. Then all array index references should be made with that instance variable.
You also have the same line of code to calculate a random number and set a label repeated 3 times. Create a new method for that and call that function from the three places you have it now.
There are two ways you can do this:
The first way is to store the string you got from your random method. You can declare a global variable for this in your class. And I suggest that you always place a block of similar code in another method.
NSString *generatedString;
- (NSString *)generateRandomString
{
generatedString = [self.myArray objectAtIndex:arc4random() % [myArray count]];
return generatedString;
}
Then in your implementation:
- (void)viewDidLoad
{
self.myLabel.text = [self generateRandomString];
}
- (IBAction)buttonA:(id)sender
{
self.myLabel.text = [self generateRandomString];
}
- (IBAction)buttonA:(id)sender
{
[self.myArray removeObject:generatedString];
self.myLabel.text = [self generateRandomString];
}
Another way is to store the index of the string generated:
NSInteger generatedStringIndex;
- (NSString *)generateRandomString
{
generatedStringIndex = arc4random() % [myArray count];
NSString generatedString = [self.myArray objectAtIndex:generatedStringIndex];
return generatedString;
}
Then in your implementation:
- (void)viewDidLoad
{
self.myLabel.text = [self generateRandomString];
}
- (IBAction)buttonA:(id)sender
{
self.myLabel.text = [self generateRandomString];
}
- (IBAction)buttonA:(id)sender
{
[self.myArray removeObject:generatedStringIndex];
self.myLabel.text = [self generateRandomString];
}
So, I have a UIPicker view which gets populated from a NSMutableArray as long as the input is not "NULL".
So my picker shows all the values except NULL.
Now, I have a UITextField box and a button. So whatever I type in the text field, and I click the button, if it matches to anything which was there in the NSMutableArray ( which was used to populate UIPickerView ), it sets it to NULL and refreshes the UIPicker so that it doesn't get displayed anymore.
For some reason, I'm able to set the value to NULL(checked using NSLog), but the picker never gets updates, and neither does the NSMutable Array.
-(void) loadthepicker
{
NSMutableArray *getarray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"FilerNamesArray"]];
pickerLoaderArray=[[NSMutableArray alloc] init];
for (int j=0; j<20; j++) {
if ([[getarray objectAtIndex:j] isEqualToString:#"NULL"])
{
// do nothing..don't load
}
else // add that filter to pickerLoaderArray
{
[pickerLoaderArray addObject:[getarray objectAtIndex:j]];
}
} // end of for
[pickerView reloadAllComponents];
[pickerView selectRow:0 inComponent:0 animated:NO];
}
-(NSInteger)numberOfComponentsInPickerView:(NSInteger)component
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)picker numberOfRowsInComponent:(NSInteger)component
{
return [pickerLoaderArray count];
}
-(NSString *)pickerView:(UIPickerView *)picker titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [pickerLoaderArray objectAtIndex:row];
}
The button:
- (IBAction)deleteButton:(id)sender {
NSUserDefaults *CheckFiltersUsed = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [CheckFiltersUsed integerForKey:#"FiltersUsed"];
if (myInt<=20 && myInt>0) {
NSLog(#"number of filters used before deleting %ld",(long)myInt);
[CheckFiltersUsed setInteger:myInt-1 forKey:#"FiltersUsed"];
[CheckFiltersUsed synchronize];
// get names array
NSMutableArray *getarray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"FilerNamesArray"]];
NSArray *get=getarray;
// at location where name matches with selectedfilter..put NULL
for (int j=0; j<20; j++) {
if ( [[getarray objectAtIndex:j] isEqualToString:_filterToDelete.text] && isFilterDeleted==NO )
{
NSLog(#"------currently %d is %#",j,[getarray objectAtIndex:j]);
[getarray insertObject:#"NULL" atIndex:j];
NSLog(#"------now %d is %#",j,[getarray objectAtIndex:j]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"" message: #"Deleted" delegate: nil cancelButtonTitle:#"Ok" otherButtonTitles:nil]; [alert show];
isFilterDeleted=YES;
[[NSUserDefaults standardUserDefaults] setObject:getarray forKey:#"FilerNamesArray"];
[[NSUserDefaults standardUserDefaults]synchronize];
[self loadthepicker];
}
else
{
NSLog(#"No matching filter name");
}
} // end of for
//now save this array back.
}
else
{
NSUserDefaults *CheckFiltersUsed = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [CheckFiltersUsed integerForKey:#"FiltersUsed"];
NSLog(#"Wrong number of filters!!!... %d",myInt);
}
}
If i get what you are trying to do, you want to delete the equal string from the array and the picker as well. But instead of that you just insert another NSString object into index 'j'
In the deleteButton method:
Instead of this line
[getarray insertObject:#"NULL" atIndex:j];
Call
[getarray removeObjectAtIndex:j];
**Update
In the loadPicker just remove the if statment to check if the string is equal to #"NULL"
So instead of:
for (int j=0; j<20; j++) {
if ([[getarray objectAtIndex:j] isEqualToString:#"NULL"])
{
// do nothing..don't load
}
else // add that filter to pickerLoaderArray
{
[pickerLoaderArray addObject:[getarray objectAtIndex:j]];
}
}
Do:
for(NSString *pickerValue in getarray){
[pickerLoaderArray addObject:pickerValue];
}
i had read this topic How to save My Data Type in NSUserDefault? and get from there this useful part of code:
MyObject *myObject = [[MyObject alloc] init];
NSData *myObjectData = [NSData dataWithBytes:(void *)&myObject length:sizeof(myObject)];
[[NSUserDefaults standardUserDefaults] setObject:myObjectData forKey:#"kMyObjectData"];
for saving data and this for reading
NSData *getData = [[NSData alloc] initWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"kMyObjectData"]];
MyObject *getObject;
[getData getBytes:&getObject];
its works very good when i save data in one ViewController and read it in other.
but when i whant to use it in the same class:
- (IBAction)linkedInLog:(UIButton *)sender
{
NSUserDefaults *myDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:#"linkedinfo"];
NSData *getData = [[NSData alloc] initWithData:myDefaults];
LinkedContainer *getObject;
[getData getBytes:&getObject];
if (!myDefaults) {
mLogInView = [[linkedInLoginView alloc]initWithNibName:#"linkedInLogInView" bundle:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loginViewDidFinish:)
name:#"loginViewDidFinish"
object:mLogInView];
[self.navigationController pushViewController:mLogInView animated:YES];
if ((FBSession.activeSession.isOpen)&&(mLinkedInIsLogegOn)) {
mMergeButton.hidden = NO;
}
}
else{
mLinkedInIsLogegOn= YES;
mLinkedInInfo.mConsumer = getObject.mConsumer;
mLinkedInInfo.mToken = getObject.mToken;
}
}
something going wrong. in #selector:loginViewDidFinish i am saving my data to NSUserDefaults:
-(void) loginViewDidFinish:(NSNotification*)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
mLinkedInInfo.mConsumer = mLogInView.consumer;
mLinkedInInfo.mToken = mLogInView.accessToken;
NSData *myObjectData = [NSData dataWithBytes:(void *)&mLinkedInInfo length:sizeof(mLinkedInInfo)];
NSUserDefaults *lSave = [NSUserDefaults standardUserDefaults];
[lSave setObject:myObjectData forKey:#"linkedinfo"];
[lSave synchronize];
if (mLinkedInInfo.mToken) {
mLinkedInIsLogegOn = YES;
}
}
the program always crashes when it comes to else part. If somebody knows what I am doing wrong please help me)
error message: Thread 1 : EXC_BAD_ACCESS(code=2,address 0x8) when compiling getObject.Consumer
In the vast majority of cases, this is not going to be a meaningful way to serialize your object into an NSData:
MyObject *myObject = [[MyObject alloc] init];
NSData *myObjectData = [NSData dataWithBytes:(void *)&myObject length:sizeof(myObject)];
[[NSUserDefaults standardUserDefaults] setObject:myObjectData forKey:#"kMyObjectData"];
The canonical way to do this would be for MyObject to adopt the NSCoding protocol. Based on the code you posted here, an adoption of NSCoding might look like this:
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super init])
{
mConsumer = [coder decodeObjectForKey: #"consumer"];
mToken = [coder decodeObjectForKey: #"token"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:mConsumer forKey: #"consumer"];
[coder encodeObject:mToken forKey:#"token"];
}
Once you had done that work, you would convert MyObject to and from NSData like this:
NSData* data = [NSKeyedArchiver archivedDataWithRootObject: myObject];
MyObject* myObject = (MyObject*)[NSKeyedUnarchiver unarchiveObjectWithData: data];
The code you have here is totally going to smash the stack and crash (because this line [getData getBytes:&getObject]; will cause the NSData to write bytes to the address of getObject, which is locally declared on the stack. Hence stack smashing.) Starting from your code, a working implementation might look something like this:
- (IBAction)linkedInLog:(UIButton *)sender
{
NSData* dataFromDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:#"linkedinfo"];
LinkedContainer* getObject = (LinkedContainer*)[NSKeyedUnarchiver unarchiveObjectWithData: dataFromDefaults];
if (!dataFromDefaults) {
mLogInView = [[linkedInLoginView alloc]initWithNibName:#"linkedInLogInView" bundle:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loginViewDidFinish:)
name:#"loginViewDidFinish"
object:mLogInView];
[self.navigationController pushViewController:mLogInView animated:YES];
if ((FBSession.activeSession.isOpen)&&(mLinkedInIsLogegOn)) {
mMergeButton.hidden = NO;
}
}
else{
mLinkedInIsLogegOn= YES;
mLinkedInInfo.mConsumer = getObject.mConsumer;
mLinkedInInfo.mToken = getObject.mToken;
}
}
-(void) loginViewDidFinish:(NSNotification*)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
mLinkedInInfo.mConsumer = mLogInView.consumer;
mLinkedInInfo.mToken = mLogInView.accessToken;
NSData* objectData = [NSKeyedArchiver archivedDataWithRootObject: mLinkedInInfo];
[[NSUserDefaults standardUserDefaults] setObject: objectData forKey: #"linkedinfo"];
[[NSUserDefaults standardUserDefaults] synchronize];
if (mLinkedInInfo.mToken) {
mLinkedInIsLogegOn = YES;
}
}
I agree with ipmcc 's answer, another viable option would be to add methods to your object to convert it to an NSDictionary. You could add methods to -initWithDictionary as well and should make instantiation very easy. Pull from dictionary in NSUserDefaults to use, convert to dictionary to save.
Here is an example of those 2 methods with generic data:
- (id)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
// This check serves to make sure that a non-NSDictionary object
// passed into the model class doesn't break the parsing.
if(self && [dict isKindOfClass:[NSDictionary class]]) {
NSObject *receivedFences = [dict objectForKey:#"fences"];
NSMutableArray *parsedFences = [NSMutableArray array];
if ([receivedFences isKindOfClass:[NSArray class]]) {
for (NSDictionary *item in (NSArray *)receivedFences) {
if ([item isKindOfClass:[NSDictionary class]]) {
[parsedFences addObject:[Fences modelObjectWithDictionary:item]];
}
}
}
}
// More checks for specific objects here
return self;
}
- (NSDictionary *)dictionaryRepresentation
{
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
NSMutableArray *tempArrayForFences = [NSMutableArray array];
for (NSObject *subArrayObject in self.fences) {
if([subArrayObject respondsToSelector:#selector(dictionaryRepresentation)]) {
// This class is a model object
[tempArrayForFences addObject:[subArrayObject performSelector:#selector(dictionaryRepresentation)]];
} else {
// Generic object
[tempArrayForFences addObject:subArrayObject];
}
}
[mutableDict setValue:[NSArray arrayWithArray:tempArrayForFences] forKey:#"fences"];
return [NSDictionary dictionaryWithDictionary:mutableDict];
}
This is basically boilerplate code that is generated by a program I use called JSON Accelerator. It will read a JSON string returned by an API and generate object code for you. Not really a new concept, but makes created classes for API's very easy. And this bit of code works great for creating dictionaries to be saved to NSUserDefaults. Hope this helps.
I have 8 tabs and am using customizable tabBarItems. So the user can reorder the tabs. Now my question is how do I get the order of the tabs and save that to NSUserDefaults so it remains the same whenever the user exits the app and comes back.
Here is the code I've got so far:
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:8];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave) {
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
}
No errors in that code, it just doesn't work.
What am I doing wrong?
By the way: My app is a tabBarApplication.
EDIT:
Here is what I've done.
Created a tabBar Application
Populated Views with data
Added 8 tabs with different views loaded from controllers
Then added the customizable reordering of tabs
Added the code above to save the tab order
Have do I retrieve that saved data when I relaunch the app?
EDIT 2:
I've been searching around and found a lot of info on this but very little on how.
Here is the code I have now:
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
NSMutableArray *vcArray = [NSMutableArray arrayWithCapacity:6];
NSArray *savedViews = tabBarController.viewControllers;
for (UIViewController *theVC in savedViews){
[vcArray addObject:theVC.title];
}
[[NSUserDefaults standardUserDefaults] setObject:vcArray forKey:#"tabLayout"];
}
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *tabLayout = [defaults arrayForKey:#"tabLayout"];
NSMutableArray *orderedLayout = [NSMutableArray arrayWithCapacity:6];
NSArray *defaultOrder = tabBarController.viewControllers;
for (int i =0; i < 6; i++){
for (UIViewController *theVC in defaultOrder) {
if ([theVC.title isEqualToString:[tabLayout objectAtIndex:i]]) {
[orderedLayout addObject:theVC];
}
}
}
tabBarController.viewControllers = orderedLayout;
}
Why doesn't this work, and by that I mean after I customize the tabbar and hit stop in Xcode, when I go to run it again it doesn't show my saved order. What in the world am I doing wrong? Is this the correct way to do this?
You're missing the synchronize.
Try this:
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:8];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave) {
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
[[NSUserDefaults standarduserDefaults] synchronize];
}
As #Nekto said - What doesn't work? How do you detect this?
also saving this info won't save your tabbar order... you have to fetch this order from nsuserdefault and generate the tab in that order next time ..
Here's the code I've been using
-(void) saveTabOrder
{
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:6];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave)
{
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
//[[NSUserDefaults standardUserDefaults] synchronize];
}
// NOTE -- because tabs may change between versions of the app,
// should NOT try to restore tabs if the tab count or names
// differ from the saved version.
- (void)setTabOrderIfSaved {
//return;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *savedOrder = [defaults arrayForKey:#"savedTabOrder"];
NSMutableArray *orderedTabs = [NSMutableArray arrayWithCapacity:6];
if ([savedOrder count] > 0 )
{
for (int i = 0; i < [savedOrder count]; i++) // loop through saved tabs
{
BOOL tabFound = NO;
for (UIViewController *aController in tabBarController.viewControllers) // loop through actual tabs
{
if ([aController.title isEqualToString:[savedOrder objectAtIndex:i]])
{
[orderedTabs addObject:aController];
tabFound = YES;
}
}
if (!tabFound)
{
// so the old tab order doesn't include this tab. Lets bail and use the default ordering
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"savedTabOrder"];
return;
}
}
tabBarController.viewControllers = orderedTabs;
}
}