Xcode : Storyboard and state preservation of the view controllers after quitting - ios

I am new to programming in Xcode and I am having a problem in my app (a ToDo list). Everything works just fine but when the app is quit (Not minimised) the main view controller doesn't save what is on it (A problem if you have a ToDo list). Now I want to know what code I would have to implement in order to preserve the state of a view controller upon exit and where? (The app delegate or in my main view controller window)
.m file:
#implementation RHTaskListViewController
#synthesize tasks = _tasks;
-(id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
//custom
}
return self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tasks = [[NSMutableArray alloc] init];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//Segue from Add task to task list
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddTaskSegue"])
{
UINavigationController *navCon = segue.destinationViewController;
RHAddTaskViewController *addTaskViewController = [navCon.viewControllers objectAtIndex:0];
addTaskViewController.taskListViewController = self;
}
else if ([segue.identifier isEqualToString:#"EditDoneTaskSegue"] || [segue.identifier isEqualToString:#"EditNotDoneTaskSegue"])
{
RHEditTaskViewController *editTaskViewController = segue.destinationViewController;
editTaskViewController.task = [self.tasks objectAtIndex:self.tableView.indexPathForSelectedRow.row];
}
}
//Segue from Add task to task list
//Move Items
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
RHTask *movedTask = [self.tasks objectAtIndex:fromIndexPath.row];
[self.tasks removeObjectAtIndex:fromIndexPath.row];
[self.tasks insertObject:movedTask atIndex:toIndexPath.row];
}
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
//Move Items
//Delete Items
-(void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.tasks removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
}
}
//Delete Items
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tasks.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NotDoneCellIdentifier = #"NotDoneTaskCell";
static NSString *DoneCellIdentifier = #"DoneTaskCell";
RHTask *currentTask = [self.tasks objectAtIndex:indexPath.row];
NSString *cellIdentifier = currentTask.done ? DoneCellIdentifier : NotDoneCellIdentifier;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
//Saving the tasks
//[[NSUserDefaults standardUserDefaults] setString:saveTask forKey:#"taskSaved"];
//Saving the tasks
cell.textLabel.text = currentTask.name;
return cell;
}
#pragma mark - IBActions
-(void)editButtonPressed:(id)sender
{
self.editing = !self.editing;
}
#end
.h file:
#import <UIKit/UIKit.h>
#interface RHTaskListViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *tasks;
-(IBAction)editButtonPressed:(id)sender;
#end

U can use NSUserDefaults to achieve your goal.
Take this tutorial link
Main code:
For saving:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"key1" forKey:#"todo1"];
[defaults synchronize]; // do NOT forget this line!
For retrieving:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *todo1 = [defaults objectForKey:#"key1"];
Just keep in mind , u can save NSArray, NSDictionary, NSString, NSNumber and all object that conforms to NSCoping protocol.

As gran33 already noted you can use NSUserDefaults to store your app data.
If your todo list more complex than just a list of tasks (i.e. each task has more properties like time,description,location etc...) I recommend using core data to store your data. Take a look here for a CoreData tutorial.

Related

How to Save a button selection in NSUser Defaults

*
//
// DetailTableViewController.m
// BeautifulWorld
//
// Created by Mahesh on 10/27/15.
// Copyright © 2015 Mahesh. All rights reserved.
//
#import "DetailTableViewController.h"
#import "DetailTableViewCell.h"
#import "ContentViewController.h"
#import "TableViewHeader.h"
#import UIKit;
#interface DetailTableViewController ()
#end
#implementation DetailTableViewController{
NSMutableArray* selectedPlaces;
NSDictionary* place;
NSArray* places;
}
DetailTableViewCell * detailcell ;
- (void)viewDidLoad {
[super viewDidLoad];
selectedPlaces = [[NSMutableArray alloc]init];
selectedItems = [[NSMutableArray alloc] init];
//TODO:- NSUserDefaults Attempt
selectedPlaces = [NSMutableArray arrayWithArray:(NSArray *)[[NSUserDefaults standardUserDefaults] objectForKey:#"selectedPlaces"]];
if(selectedPlaces == nil){
selectedPlaces = [[NSMutableArray alloc] init];
}else{
NSLog(#"Saved to Defaults");
}
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
detailcell.loveImageView.highlighted = YES;
self.navigationItem.title = _DetailTableModal[0];
//Wonders Of The World
//[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
//Your code goes in here
//NSLog(#"Main Thread Code");
if ([self.navigationItem.title isEqualToString:#"Wonders Of The World"])
{
NSArray* titleArray = #[#"Pyramid at 'Chichen Itza'",
#"Christ the Redeemer",
#"Great Wall of China",
#"Machu Picchu",
#"Petra",
#"Taj Mahal",
#"Colosseum ",];
Title = [titleArray mutableCopy];
NSArray* descriptionArray = #[#"Yucatan, Mexico",
#"Rio de Janeiro - RJ, Brazil",
#"China",
#"Peru",
#"Wadi Musa,Jordan",
#"Agra,Uttar Pradesh,India",
#"Rome,Italy",];
Description = [descriptionArray mutableCopy];
NSArray* imageArray = #[#"1ChichenItza.jpg",
#"2ChristtheRedeemer.jpg",
#"3GreatWallofChina.jpg",
#"4MachuPicchu.jpg",
#"5Petra.jpg",
#"6Tajmahal.jpg",
#"7Colosseum.jpg",];
Image = [imageArray mutableCopy];
}
// }];
if ([self.navigationItem.title isEqualToString:#"Sky Scrapers"])
{
NSArray* titleArray = #[#"Burj Kalifa",
#"Eiffel Tower",
#"Empire State Building",
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillAppear:(BOOL)animated{
[self myValue];
self.tabBarController.tabBar.hidden = NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return Title.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * CellIdentifier = #"DetailCell";
detailcell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
int row = (int)[indexPath row];
detailcell.DetailTableCellTitle.text = Title[row];
detailcell.DetailTableCellDescription.text = Description[row];
detailcell.DetailTableCellImageView.image= [UIImage imageNamed:Image[row]];
if([selectedItems containsObject:indexPath]){
//high
detailcell.loveImageView.highlighted = YES;
}else{
//gray
detailcell.loveImageView.highlighted = NO;
}
// Adding Tag To The Love Button
// detailcell.loveImageView.tag = indexPath.row;
detailcell.favouriteButton.tag = indexPath.row;
// Adding Tap Guesture To Love Button
detailcell.loveImageView.userInteractionEnabled = YES;
// UITapGestureRecognizer *tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(loveImageTapped:)];
// tapGesture1.numberOfTapsRequired = 1;
// [detailcell.loveImageView addGestureRecognizer:tapGesture1];
[detailcell.favouriteButton addTarget:self action:#selector(loveImageTapped:) forControlEvents:UIControlEventTouchUpInside];
return detailcell;
}
#pragma mark Delete Rows With Animation
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[Image removeObjectAtIndex:indexPath.row];
[Description removeObjectAtIndex:indexPath.row];
[Title removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
NSIndexPath * rowToReload = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
NSArray * rowsToReload = [NSArray arrayWithObjects:rowToReload, nil];
[tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationLeft];
}
#pragma mark Love Button Tapped
-(void)loveImageTapped:(UIButton*)sender {
sender.selected = !sender.selected; //calling your method
[self saveMyValue:sender.selected];
if (sender.selected) {
[sender setBackgroundImage:[UIImage imageNamed:#"HeartSelectedSmall"] forState:UIControlStateNormal];
[selectedPlaces addObject:selectedPlaces];
}else{
[sender setBackgroundImage:[UIImage imageNamed:#"Heart"] forState:UIControlStateNormal];
}
[self.tableView reloadData];
} // Your Methods Added
// Set the value
- (void)saveMyValue:(BOOL)myValue {
[[NSUserDefaults standardUserDefaults] setInteger:[NSNumber numberWithBool:myValue ].integerValue forKey:#"myActionKeyHere"];
[[NSUserDefaults standardUserDefaults] synchronize];
} // Your Methods Added
// Get the value
- (NSInteger)myValue {
NSInteger myValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"myActionKeyHere"];
return myValue ;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation To The Detail Content View.
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowDetails"]) {
ContentViewController * contentView = [ segue destinationViewController];
NSIndexPath * myindexpath = [self.tableView indexPathForSelectedRow];
int row = (int)[myindexpath row];
contentView.ContentModal = #[Title[row],Description[row],Image[row]];
}
}
#end Did The Same. Can you please explain me a bit more. What to do in cell for row at index path
*
You save it like this if its a BOOL, otherwise just change to NSInteger if you want multiple options etc:
// Set the value
- (void)saveMyValue:(BOOL)myValue {
[[NSUserDefaults standardUserDefaults] setInteger:[NSNumber numberWithBool:myValue ].integerValue forKey:#"myActionKeyHere"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
// Get the value
- (NSInteger)myValue {
NSInteger myValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"myActionKeyHere"];
return myValue ;
}
#Hauzin did tell you the way with NSUserDefaults.
By the way, I have an other idea about your case.
First of all, the type of the button's selection status is BOOL type.
So we have to box the BOOL value as NSNumber value. (with [NSNumber numberWithBool:xxx])
And then, if you have a UITableView and the UITableView needs a number of button's selection status, you can save the Button selection status as a NSArray.
Then you could write a method with a NSArray type argument to create the new UITableView. (e.g: - (void)setupXXXtableViewWithButtonStatus:(NSArray *)buttonStatusArray;)
If you want to save button state in NSUserDefault you can use following code.
NSUserDefaults *udefaults=[NSUserDefaults standardUserDefaults];
if (btn.selected) {
[udefaults setBool:YES forKey:#"isSelected"];
}else{
[udefaults setBool:NO forKey:#"isSelected"];
}
To get the state of button you can use.
NSUserDefaults *udefaults=[NSUserDefaults standardUserDefaults];
BOOL isButtonSelected = [udefaults boolForKey:#"isSelected"];
Also, don't forget to call synchronize on udefaults like this.
[udefaults synchronize];
Hope, it helps.

How to save the checkmarks in uitableview and show them when the user comes back again to the view?

I am using the following code for showing the checkmarks in the uitableview
{
// NSArray *tableContents;
NSMutableArray *selectedMarks; // You need probably to save the selected cells for use in the future.
}
#property (strong, nonatomic) IBOutlet UITableView *languageTableView;
#property (nonatomic, strong) NSArray *tableContents;
#end
#implementation QPLanguageSettingsController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initialisation];
selectedMarks = [NSMutableArray new];
}
#pragma mark - View Life Cycle
-(void)initialisation
{
_tableContents = [NSArray arrayWithObjects:#"English",#"Spanish",#"Russian",#"Arabic",#"Portuguese",#"French",#"German",#"German",#"German",#"German",#"German",#"German",#"German",#"German", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITableView delegate & datasources
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 14;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newFriendCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//etc.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.textColor = [UIColor whiteColor];
cell.backgroundColor = [UIColor clearColor];
[cell setIndentationLevel:3];
[cell setIndentationWidth:10];
NSString *text = [_tableContents objectAtIndex:[indexPath row]];
//cell.isSelected = [selectedMarks containsObject:text] ? YES : NO;
cell.textLabel.text = text;
NSDictionary *item = [_tableContents objectAtIndex:indexPath.row];
if ([selectedMarks containsObject:item])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//if you want only one cell to be selected use a local NSIndexPath property instead of array. and use the code below
//self.selectedIndexPath = indexPath;
//the below code will allow multiple selection
NSDictionary *item = [_tableContents objectAtIndex:indexPath.row];
if ([selectedMarks containsObject:item])
{
[selectedMarks removeObject:item];
}
else
{
[selectedMarks addObject:item];
}
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
But the problem is that when i come again to the view controller all the checkmarks disappears. how to solve it. Remember i am using multiple selection in uitableview.
I tried the to get solution for your question.I got it successfully.It works perfectly.
This is sample one.Try this code.It works fine.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableViewCheckMarkPreviousSelectionUpdate;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrProductSelection,*arrProductSelectDeSelectCheckMark;
NSArray *arrayFetchFromDefaults;
}
#end
#implementation ViewController
#synthesize tableViewCheckMarkPreviousSelectionUpdate;
- (void)viewDidLoad
{
[super viewDidLoad];
arrProductSelection = [[NSMutableArray alloc]initWithObjects:#"iPhone",#"iPad",#"iPod",#"iTV",#"iWatch",#"iMac",nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillAppear:(BOOL)animated
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
arrayFetchFromDefaults = [userDefaults objectForKey:#"selectedcheckmark"];
arrProductSelectDeSelectCheckMark = [[NSMutableArray alloc]initWithArray:arrayFetchFromDefaults];
if(arrProductSelectDeSelectCheckMark.count == 0)
{
arrProductSelectDeSelectCheckMark = [[NSMutableArray alloc]init];
for(int j=0;j<[arrProductSelection count];j++)
{
[arrProductSelectDeSelectCheckMark addObject:#"deselected"];
}
}
[tableViewCheckMarkPreviousSelectionUpdate reloadData];
}
#pragma mark - UITableViewDataSource Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrProductSelection.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *strCell = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if(cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCell];
}
if([[arrProductSelectDeSelectCheckMark objectAtIndex:indexPath.row] isEqualToString:#"deselected"])
cell.accessoryType = UITableViewCellAccessoryNone;
else
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.textLabel.text = [arrProductSelection objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate Methods
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
#try
{
CGPoint touchPoint = [cell convertPoint:CGPointZero toView:tableViewCheckMarkSelectionUpdate];
NSIndexPath *indexPath = [tableViewCheckMarkSelectionUpdate indexPathForRowAtPoint:touchPoint];
NSLog(#"%#",arrProductSelectDeSelectCheckMark);
if([arrProductSelectDeSelectCheckMark count]==0)
{
for(int i=0; i<[arrProductSelection count]; i++)
{
[arrProductSelectDeSelectCheckMark addObject:#"deselected"];
}
}
if([[arrProductSelectDeSelectCheckMark objectAtIndex:indexPath.row] isEqualToString:#"deselected"])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arrProductSelectDeSelectCheckMark replaceObjectAtIndex:indexPath.row withObject:#"selected"];
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
[arrProductSelectDeSelectCheckMark replaceObjectAtIndex:indexPath.row withObject:#"deselected"];
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:arrProductSelectDeSelectCheckMark forKey:#"selectedcheckmark"];
[defaults synchronize];
}
#catch (NSException *exception) {
NSLog(#"The exception is-%#",exception);
}
}
#end
You have multiple solutions:
Using a rational DB on the device like Core-data or SQLite which actually fits your use case but number 3 is more suitable for your use case.
Using NSUserDefaults:
At runtime, you use an NSUserDefaults object to read the defaults that your application uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default
You can find an example here. But NSUserDefaults is to save settings/config/setup information or perhaps user info and NOT for the use case you need.
Using NSCoder which is in my opinion fits your use case.
you can create a Singleton and store data on it :
Singleton.h
#interface Singleton : NSObject
#property (nonatomic, strong) NSArray *rowsChecked;
+ (Singleton *)sharedInstance;
+ (NSArray *)getRowsChecked;
+ (void)setRowsChecked:(NSArray *)rowsChecked;
#end
Singleton.m
#import "Singleton.h"
#implementation Singleton
static Singleton *sharedObject;
+ (Singleton *)sharedInstance;
{
if (sharedObject == nil) {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedObject = [[Singleton alloc] init];
});
}
return sharedObject;
}
+ (NSArray *)getRowsChecked
{
Singleton *singleton = [Singleton sharedInstance];
return singleton.rowsChecked;
}
+ (void)setRowsChecked:(NSArray *)rowsChecked
{
Singleton *singleton = [Singleton sharedInstance];
singleton.rowsChecked= rowsChecked;
}
#end
and to access to your Singleton :
[[Singleton sharedInstance] getRowsChecked]
// or
[[Singleton sharedInstance] setRowsChecked:anArray];
Use the following code:
#import "ViewController.h"
#interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *languagesTableView;
#property (strong, nonatomic) NSArray *languagesArray;
#property (strong, nonatomic) NSMutableArray *checkMarksArray;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.languagesTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
self.languagesArray = [NSArray arrayWithObjects:#"English",#"Spanish",#"Russian",#"Arabic",#"Portuguese",#"French",#"German", nil];
self.checkMarksArray = [[NSMutableArray alloc]init];
if( [[NSUserDefaults standardUserDefaults]objectForKey:#"selectedRowsArray"])
{
self.checkMarksArray = [[[NSUserDefaults standardUserDefaults]objectForKey:#"selectedRowsArray"] mutableCopy];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.languagesArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *languagesCell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
languagesCell.textLabel.text = self.languagesArray[indexPath.row];
if([self.checkMarksArray containsObject:[NSNumber numberWithLong:indexPath.row]])
{
languagesCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
languagesCell.accessoryType = UITableViewCellAccessoryNone;
}
[[NSUserDefaults standardUserDefaults]setObject:self.checkMarksArray forKey:#"selectedRowsArray"];
[[NSUserDefaults standardUserDefaults]synchronize];
return languagesCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if([self.checkMarksArray containsObject:[NSNumber numberWithLong:indexPath.row]])
{
[self.checkMarksArray removeObject:[NSNumber numberWithLong:indexPath.row]];
}
else
{
[self.checkMarksArray addObject:[NSNumber numberWithLong:indexPath.row]];
}
[self.languagesTableView reloadData];
}
#end
Check this GitHub link:
https://github.com/k-sathireddy/TableViewSelectedCheckMarks

Update core data object on UITableViewCell touch

I have a simple todo app, where a user can touch a cell to check/uncheck a task. But I am not sure how to update Core Data setting the boolean value of completed to yes.
Here is my code:
//
// PakkelisteViewController.m
// Sommerleir
//
// Created by Ronny-André Bendiksen on 08.05.14.
// Copyright (c) 2014 Arbeidernes Ungdomsfylking. All rights reserved.
//
#import "PakkelisteViewController.h"
#import "AUFToDoItem.h"
#import "TodoCell.h"
#interface PakkelisteViewController ()
#property NSMutableArray *toDoItems;
-(IBAction)addNewToDoItem;
#end
#implementation PakkelisteViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)viewWillAppear:(BOOL)animated
{
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"AUFToDoItem"];
self.toDoItems = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
-(void)loadInitialData
{
// check if user has already been using this functionality
BOOL hasRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"PakkelisteHasRun"];
if (!hasRunBefore)
{
NSLog(#"Has not run");
[self.toDoItems addObjectsFromArray:#[#"Badetøy", #"Skrivesaker", #"Lommepenger", #"Godt humør"]];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"PakkelisteHasRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
else
{
NSLog(#"Already run");
}
}
-(IBAction)addNewToDoItem
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Legg til ny" message:nil delegate:self cancelButtonTitle:#"Avbryt" otherButtonTitles:#"Legg til", nil];
[alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
[[alertView textFieldAtIndex:0] setPlaceholder:#"Rent undertøy"];
[[alertView textFieldAtIndex:0] setAutocapitalizationType:UITextAutocapitalizationTypeSentences];
[alertView show];
}
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
NSString *inputText = [[alertView textFieldAtIndex:0] text];
if ([inputText length] > 0)
{
return YES;
}
else
{
return NO;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:#"AUFToDoItem" inManagedObjectContext:context];
[toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:#"itemName"];
[toDoItem setValue:[NSDate date] forKey:#"creationDate"];
[toDoItem setValue:[NSNumber numberWithBool:YES] forKey:#"completed"];
[self.toDoItems addObject:toDoItem];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView reloadData];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.toDoItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
TodoCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[TodoCell alloc] init];
}
NSManagedObject *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.title.text = [toDoItem valueForKey:#"itemName"];
if ([[toDoItem valueForKey:#"completed"] boolValue] == 1)
{
cell.checkbox.image = [UIImage imageNamed:#"checkbox_on.png"];
}
else
{
cell.checkbox.image = [UIImage imageNamed:#"checkbox_on.png"];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
[tableView deselectRowAtIndexPath:indexPath animated:NO];
AUFToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
tappedItem.completed = !tappedItem.completed;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
*/
}
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[context deleteObject:[self.toDoItems objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Can't delete! %# %#", error, [error localizedDescription]);
return;
}
[self.toDoItems removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
/*
#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
Change:
tappedItem.completed = !tappedItem.completed;
to:
tappedItem.completed = #(![tappedItem.completed boolValue]);
Which is a minimal code unpacking and re packing of the bool value in an NSNumber instance.
Also, in your if statement, don't check if a BOOL value == 1 because that isn't necessarily true. Just say:
if ([tappedItem.completed]) { ...
You also appear to have a typo in the names of the checkbox images you're using.
What if move the code to update the status of your cell in tableView:tableView didSelectRowAtIndexPath:? In addition, can you explain what you mean with But I am not sure how to update Core Data setting the boolean value of completed to yes?
After updating the status of your managed object you save the context you are using, then you can perfom a reload on the entire table or on a specific index path.
BOOL hasTap = ![tappedItem.completed boolValue];
tappedItem.completed = #(hasTap); // or [NSNumber numberWithBool:hasTap];
// save
// reload
I really follow Jonathan's comment. A NSFetchedResultsController is made to wotk with UITableViews (or UICollectionViews). You can set its delegate, NSFetchedResultsControllerDelegate, to listen and handle for inserting, deleting, moving rows (and section).
An tutorial would be Core Data Tutorial for iOS: How To Use NSFetchedResultsController.

UITableView select Segue not working

I am new to iOS and I do not understand why when I click on my item in the cell it goes nowhere. No errors, no nothing. My segue ID is Cell. I Have a Button that works fine to add data, but I am trying to get to update the data if selected from the table.
Here is my .h and .m
DerbyProTableViewController.h:
#import <UIKit/UIKit.h>
#interface DerbyProTableViewController : UITableViewController
#property (strong) NSMutableArray *racerarray;
#end
DerbyProTableViewController.m:
#import "DerbyProTableViewController.h"
#import "DerbyProDetailViewController.h"
#interface DerbyProTableViewController ()
#end
#implementation DerbyProTableViewController
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Racer"];
self.racerarray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.racerarray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *device = [self.racerarray objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%# %#", [device valueForKey:#"lastname"], [device valueForKey:#"firstname"]]];
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.racerarray objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.racerarray removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"updateracer"]){
NSManagedObject *selectedDevice = [self.racerarray objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
DerbyProDetailViewController *destinationViewController = segue.destinationViewController;
destinationViewController.derbyprodb = selectedDevice;
}
}
I'm going on just what I see in the code you pasted. I don't know what might have been setup in the storyboard but...
There's no delegate or datasource specified for the UITableView object. The UITableViewDelegate handles cell selection.
Once you've set up the delegate like this:
[self.tableview setDelegate:self];
You then need to implement:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"whateveryoursegueiscalled" sender:thecellyoutapped];
}
Have a read of Apple's tableview programming guide.
Chances are that you didn't add your class in the Identity inspector in your storyboard.
Select your view in the storyboard and click on identity ispector. Ensure that Class field is not empty

Saving Method for a button

this is my code in my .m file
#interface HomeWorkViewController ()
#end
#implementation HomeWorkViewController
#synthesize adView;
#synthesize myTableView, numbers;
-(void) viewDidLoad
{
adView.delegate=self;
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
// check here if key exists in the defaults or not, if yes the retrieve results in array
if([[NSUserDefaults standardUserDefaults] objectForKey:#"numberArray"] != nil) {
self.numbers = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"numberArray"]];
}
//Register for the notification when user go to background or minimize the app, just save the array objects in the defaults
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillGoToBackground:)
name:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication]];
//Add the Add button
UIBarButtonItem * addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target: self action: #selector(insertNewObject)];
self.navigationItem.rightBarButtonItem = addButton;
}
-(void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.myTableView setEditing:editing animated:animated];
}
-(void)appWillGoToBackground:(NSNotification *)note {
NSLog(#"terminate");
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setObject:self.numbers forKey:#"numberArray"];
[defaults synchronize];
}
-(void)insertNewObject{
//Display a UIAlertView
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Enter HomeWork" message: #"" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Only perform the following actions if the user hits the ok button
if (buttonIndex == 1)
{
NSString * tmpTextField = [alertView textFieldAtIndex:0].text;
if(!self. numbers){
self.numbers = [[NSMutableArray alloc]init];
}
[self.numbers insertObject:tmpTextField atIndex:0];
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.myTableView insertRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.numbers.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"cell";
UITableViewCell *cell = [ tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier: cellIdentifier];
}
cell.textLabel.text = [self.numbers objectAtIndex:indexPath.row];
return cell;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
//remove our NSMutableArray
[self.numbers removeObjectAtIndex:indexPath.row];
//remove from our tableView
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
adView.hidden=FALSE;
NSLog(#"Has ad, showing");
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
adView.hidden=TRUE;
NSLog(#"Has no ads, hiding");
}
-(void)dealloc
{
[adView release];
[super dealloc];
}
#end
I have a saving method there but I want to save everything that I changed in the table by clicking a button. How do i do that?
I want to put a toolbar with a button that says back to go to the home screen, and link this button to save everything that was done to the table like delete, switch order and add.
You're almost there :)
You are using the numbers array as the data model for the table.
Make sure that this array is always updated when the table is manipulated. (For example, you need to reorder the numbers array in moveRowAtIndexPath. Currently, you do nothing in that method)
To save the model using a button, just create a UIButton in the Interface Builder and connect it to the following action:
- (IBAction)saveButtonWasPressed:(id)sender {
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setObject:self.numbers forKey:#"numberArray"];
[defaults synchronize];
}
Maybe you also want to pop the tableviewcontroller from the navigationcontroller stack if you also want to leave the controller.

Resources