Pass information to UIAlertView delegate - ios

I'm trying to delete a row in table view after confirmation from the user, using an alert view. However I don't know how to let the UIAlertViewDelegate method know which row in the table to delete.
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertView *alert_delete = [[UIAlertView alloc]initWithTitle:[NSString stringWithFormat:#"Confirm Delete %#",[names objectAtIndex:indexPath.row] ] message:#"Warning all student data will be earsed" delegate:self cancelButtonTitle:#"Dismess" otherButtonTitles:#"YES", nil];
[alert_delete show];
// 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
}
}
in alert method i try handle it to delete row from table and database
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString*title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"YES"]) {
// how to pass indexPath.row to alertview
[names removeObjectAtIndex:indexPath.row];
}
}

If you want to pass something to the delegate then add a property to the delegate class and pass the information to it before invoking the alert view:
#interface AlertDelegate : NSObject <UIAlertViewDelegate>
#property (nonatomic) NSIndexPath *indexPath;
#end
// #implementation AlertDelegate omitted
And use thus:
UIAlertView *alertView = ...;
AlertDelegate *delegate = [AlertDelegate new];
alertView.delegate = delegate;
delegate.indexPath = indexPathFromSomewhere;
[alertView show]; // or whatever
If the delegate is self, then that means adding the property to self (or use a private instance variable).
In the delegate method you then have access to the indexPath:
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString*title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"YES"]) {
[names removeObjectAtIndex:self.indexPath.row];
}
}

Add a variable to your tableView controller class to hold the indexPath.row and then use it in the alertview. Save indexPath.row in it before showing the alert.
Also you need to call
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
after confirming that user selected YES in the alertView delegate method.

You can also use objc_setAssociatedObject if info to be passed is a collection object. link -
How do you pass a variable to the UIAlertView delegate?

Instead UIAlertview use
CustomAlertview CustomAlertView *lAlert = [[CustomAlertView alloc] init.....
#import <UIKit/UIKit.h>
#interface CustomAlertView : UIAlertView
#property (nonatomic,retain)NSString *mIndex;
#end
#import "CustomAlertView.h"
#implementation CustomAlertView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
In the delegate method get the selected data or index as below
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"index %#",((CustomAlertView *)alertView).mIndex);
}
In the table delegate method assing the index or data as below
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
CustomAlertView *lAlert = [[CustomAlertView alloc] .....
lAlert.mIndex = #"1";
[lAlert show];
lAlert = nil;
}

Related

Refresh main view after choosing calendar and hitting back button

I followed this tutorial from AppCoda and I noticed that when I create another calendar, choose it (indicated by the checkmark beside it), then hit the Back button, the events in the main UIViewController view are not refreshed. I already added this code in my ViewController.m but nothing new happened:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.tblEvents == nil) {
NSLog(#"Your TableView becomes nil");
return;
}
[self.tblEvents reloadData];
}
Any ideas? Let me know if you need more information.
Edit:
.m
#import "MainViewController.h"
#import "AppDelegate.h"
#interface MainViewController ()
#property (nonatomic, strong) AppDelegate *appDelegate;
#property (nonatomic, strong) NSArray *arrEvents;
- (void)requestAccessToEvents;
- (void)loadEvents;
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.tblEvents.delegate = self;
self.tblEvents.dataSource = self;
[self performSelector:#selector(requestAccessToEvents) withObject:nil afterDelay:0.4];
[self performSelector:#selector(loadEvents) withObject:nil afterDelay:0.5];
[self.tblEvents reloadData];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tblEvents reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"idSegueEvent"]) {
EventViewController *eventViewController = [segue destinationViewController];
eventViewController.delegate = self;
}
}
#pragma mark - UITableView Delegate and Datasource method implementation
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"%lu", (unsigned long)self.arrEvents.count);
return self.arrEvents.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"idCellEvent"];
// Get each single event.
EKEvent *event = [self.arrEvents objectAtIndex:indexPath.row];
// Set its title to the cell's text label.
cell.textLabel.text = event.title;
// Get the event start date as a string value.
NSString *startDateString = [self.appDelegate.eventManager getStringFromDate:event.startDate];
// Get the event end date as a string value.
NSString *endDateString = [self.appDelegate.eventManager getStringFromDate:event.endDate];
// Add the start and end date strings to the detail text label.
cell.detailTextLabel.text = [NSString stringWithFormat:#"%# - %#", startDateString, endDateString];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60.0;
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// Keep the identifier of the event that's about to be edited.
self.appDelegate.eventManager.selectedEventIdentifier = [[self.arrEvents objectAtIndex:indexPath.row] eventIdentifier];
// Perform the segue.
[self performSegueWithIdentifier:#"idSegueEvent" sender:self];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the selected event.
[self.appDelegate.eventManager deleteEventWithIdentifier:[[self.arrEvents objectAtIndex:indexPath.row] eventIdentifier]];
// Reload all events and the table view.
[self loadEvents];
}
}
#pragma mark - EEventViewControllerDelegate method implementation
- (void)eventWasSuccessfullySaved
{
// Reload all events.
[self loadEvents];
}
#pragma mark - IBAction method implementation
- (IBAction)showCalendars:(id)sender
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
[self performSegueWithIdentifier:#"idSegueCalendars" sender:self];
}
}
- (IBAction)createEvent:(id)sender
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
[self performSegueWithIdentifier:#"idSegueEvent" sender:self];
}
}
#pragma mark - Private method implementation
- (void)requestAccessToEvents
{
[self.appDelegate.eventManager.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (error == nil) {
// Store the returned granted value.
self.appDelegate.eventManager.eventsAccessGranted = granted;
} else {
// In case of error, just log its description to the debugger.
NSLog(#"%#", [error localizedDescription]);
}
}];
}
- (void)loadEvents
{
if (self.appDelegate.eventManager.eventsAccessGranted) {
self.arrEvents = [self.appDelegate.eventManager getEventsOfSelectedCalendar];
[self.tblEvents reloadData];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
To make UITableView work you need to set the delegate and datasource object like this..
in you ViewController.m file try to add Delegate and DataSource like this.
#interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
#end
now add these two lines in your view did load.
self.tblEvents.delegate = self;
self.tblEvents.dataSource = self;
And check the implimentation of you Data Source methods like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//This method should return the number of rows you want to create in your tableView
return yourArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourCellIdentifier"];
//Now show what you want to show in your each cell? For Example you just want to show a simple text which is stored in you array.
cell.textLabel.text = [yourArray objectAtIndex:indexPath.row];
//indexPath.row is the numeric index number of each cell. This method will automatically execute exact the same number of time you return in above method.
return cell;
}
Now When your class/View Controller is open you might have zero data in your array and after some manipulation you got some data in your array Either by Call Web-Services/Loading from local Database/ by Passing Reference of array to next ViewController and on coming back to screen you want to refresh your TableView so now calling [tblEvents reloadData] will restart the process from numberOfRowsInSection method to cellForRowAtIndexPath method

How to add a CollectionView to a ViewController

I want to add a CollectionView inside my ViewController using the same code that I have on a CollectionViewController.
CollectionViewController.m
#interface StoreViewController ()
#property (readwrite, nonatomic, strong) NSArray *latestProducts;
#end
#implementation StoreViewController
- (void)setLatestProducts:(NSArray *)latestProducts {
_latestProducts = latestProducts;
[self.collectionView reloadData];
}
- (Product *)releaseForIndexPath:(NSIndexPath *)indexPath {
return [self.latestProducts objectAtIndex:indexPath.row];
}
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
#pragma mark - UICollectionViewDelegate
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.latestProducts count];
}
#pragma mark - Collection View Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"productCell";
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.product = [self releaseForIndexPath:indexPath];
return cell;
}
#end
ProductCell.m
#implementation ProductCell
- (void)setProduct:(Product *)product {
_product = product;
dispatch_async(dispatch_get_main_queue(), ^{
[self.image setImageWithURL:self.product.thumbnailImageURL];
});
self.image.clipsToBounds = YES;
}
#end
I have an NSObject that parses my cell's content, from my database.
Product.h
#interface Product : NSObject
#property (readonly) NSURL *thumbnailImageURL;
- (instancetype)initWithAttributes:(NSDictionary *)attributes;
+ (void)latestProductsWithBlock:(void (^)(NSArray *products, NSError *error))block;
#end
Following a tutorial I fount online, I created a NSObject file ("ProductDataSource") and on my Storyboard I added an Object to my ViewController and linked it to my CollectionView. I copied the code from my CollectionViewController to ProductDataSource but it's not creating my cells. If I set the numberOfItemsInSection to a number it created the cells but not when I change the code to return [self.latestProducts count]. It might have something to do with "loadData" section I have on my CollectionViewController, since ProductDataSource doesn't have a viewDidLoad method.
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
Any help? Thanks.
You have to reload the collection view after you get latestProducts. Try to put [self.collectionView reloadData] after [self hideLoadingView];
Put a breakpoint in your cellForItemAtIndexPath method to ensure that method is being hit. If it doesn't get hit, that means you need to set your collection view's datasource.
So if I am understanding correctly, you have an existing UICollectionViewController called CollectionViewController and want to reuse the logic in another UIViewController.
a UICollectionViewController is essentially a UIViewController that has a UICollectionView subview and conforms to the UICollectionViewDataSource and UICollectionViewDelegate protocols.
In order to embed a UICollectionView into your UIViewController, you need to create Delegate and DataSource classes for your CollectionView and assign them in the UIViewController.
There are some good code examples here: UICollectionView with UIViewController As Data Source
GitHub Repo with a small single page app using a CollectionView inside a UIViewController:
https://github.com/pnavk/CollectionViewSample

unrecognized selector at popover segue

I'm using this code in my app to pass data with the corresponding seque:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"readMoreDetail"]) {
MoreViewController *destinationViewController = segue.destinationViewController;
destinationViewController.openSubject = [self.detailItem description];
} else if ([segue.identifier isEqualToString:#"notesSegue"]) {
NSLog(#"segue");
NotesTableViewController *destinationViewController = segue.destinationViewController;
destinationViewController.openSubject = [self.detailItem description];
} else {
// Do nothing
}
}
I've embedded a UIViewController in a NavigationController and created a popover segue from another UIViewController to the NavigationController - but when I navigate I get this error:
-[UINavigationController setOpenSubject:]: unrecognized selector sent to instance 0x15e532a0
Any ideas why?
Thanks!
NotesTableViewController.h
#import <UIKit/UIKit.h>
#interface NotesTableViewController : UITableViewController <UINavigationControllerDelegate>
#property(nonatomic, strong)NSString *openSubject;
#end
NotesTableViewController.m
#import "NotesTableViewController.h"
#interface NotesTableViewController ()
{
NSMutableArray *_objects;
}
#end
#implementation NotesTableViewController
#synthesize openSubject;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (openSubject.length == 0) {
// There's currently no subject open, write it in the navigationbar
// Prompt = open subject
// Title = notes header
self.navigationItem.prompt = #"No subject selected";
self.navigationItem.title = #"My Notes";
} else {
// Open the subject
// Prompt = notes header
// Title = open subject
self.navigationItem.prompt = openSubject;
self.navigationItem.title = #"My notes";
// Load the notes data
// Create the key
NSString *partOfKey = #"-notes";
NSString *notesKey = [NSString stringWithFormat:#"%#%#", openSubject, partOfKey];
// Load the _objects from NSUserdefaults
_objects = [[NSUserDefaults standardUserDefaults] objectForKey:notesKey];
}
// 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.leftBarButtonItem = self.editButtonItem;
// Register a class or nib file using registerNib:forCellReuseIdentifier
// o registerClass:forCellReuiseIdentifier: method before calling this method
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
- (void)awakeFromNib
{
self.clearsSelectionOnViewWillAppear = NO;
self.preferredContentSize = CGSizeMake(320.0, 600.0);
[super awakeFromNib];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)addNote:(id)sender {
// Create a new note
if (openSubject.length == 0) {
// The openSubject is nil, can't add a subject - tell the user
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"No subject" message: #"Please select a subject prior to adding a note" delegate: nil cancelButtonTitle:#"OK" otherButtonTitles:nil]; [alert show];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"New note" message:#"Enter a note" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Add", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
// The user created a new subject, add it
if (buttonIndex == 1) {
// Get the input text
NSString *newNote = [[alertView textFieldAtIndex:0] text];
// Initialize objects
if (!_objects) {
_objects = [[NSMutableArray alloc] init];
}
// Check if the note already exist
if ([_objects containsObject:newNote]) {
// Tell the user this note already exists
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Already exists" message: #"This note already exist, sorry" delegate: nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
} else {
// The note doesn't exist, add it
[_objects insertObject:newNote atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
// Save the new _objects
[self saveObjects];
}
}
}
-(void)saveObjects {
// Create the key
NSString *partOfKey = #"-notes";
// Save the new objects
NSString *notesKey = [NSString stringWithFormat:#"%#%#", openSubject, partOfKey];
[[NSUserDefaults standardUserDefaults] setObject:_objects forKey:notesKey];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return _objects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSString *object = _objects[indexPath.row];
cell.textLabel.text = [object description];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_objects removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Save the new objects
[self saveObjects];
} 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.
}
}
/*
// 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 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
(I trust everyone to not steal this code)
If you trigger a segue to a UINavigationController the segue.destinationViewController will be the navigation controller and not the view controller contained in the navigation controller.
You can however get a reference to your NotesTableViewController:
UINavigationController *navController = segue.destinationViewController;
NotesTableViewController *notesTableVC = (NotesTableViewController *)[navController topViewController];
and then you can use
notesTableVC.openSubject = [self.detailItem description];
etc. to set the properties in your NotesTableViewController.
make sure your segue Identifiers are identified correctly as "notesSegue" and "readMoreDetail" , sometime you have to clean the project and run it again.

After adding new cell, how to get the UITableViewControler to save the new entry, so when app is closed and re opened the new cell is there

Ok, so I'm new to iOS Development. I have just created a master view application for note taking. Every thing works fine except for one thing, after a new cell is created and i stop the app and reopen the app the new cell is not there!
Thanks in advance!
Master View Controller.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController () {
NSMutableArray *_objects;
}
#end
#implementation MasterViewController
#synthesize myTableView, numbers;
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//NSMT arry
numbers = [[NSMutableArray alloc]initWithObjects:#"One",#"Two",#"Three",#"Four", nil];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
}
- (void)viewWillAppear:(BOOL)animated {
}
-(void)viewWillDisappear:(BOOL)animated{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)insertNewObject:(id)sender
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Enter" message:#"" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
/*
if (!numbers) {
numbers = [[NSMutableArray alloc] init];
}
[numbers insertObject:[NSDate date] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
*/
}
-(void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[myTableView setEditing:editing animated:animated];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return numbers.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [numbers objectAtIndex:indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[numbers removeObjectAtIndex:indexPath.row];
[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)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//if user hits OK
if (buttonIndex == 1) {
NSString * tempTextField = [alertView textFieldAtIndex:0].text;
if (!numbers) {
numbers = [[NSMutableArray alloc] init];
}
[numbers insertObject:tempTextField atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.myTableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
/*
// 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;
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = _objects[indexPath.row];
[[segue destinationViewController] setDetailItem:object];
}
}
#end
MasterViewController.h
#import <UIKit/UIKit.h>
#interface MasterViewController : UITableViewController
<UITableViewDataSource, UITableViewDelegate, UIAlertViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
#property (strong, nonatomic) NSMutableArray * numbers;
#end
Perhaps tell us how you're storing the data used to populate the tableview. As this is what you need to save.
You could save it using CoreData or just use NSUserDefaults, there are plenty of options open to you. However, without knowing how you data is currently structured it's hard to give you a specific example.
Show some code and you'll get a better answer.

Crashing On TableView insertRowsAtIndexPath

My app was running fine, I've not modified it to have a dedicated data controller class rather than the data being handled in the main UI class as it was during initial testing. However since the change it keeps crashing when adding a new item to the tableview.
The line of code and error it's crashing on are;
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
2012-07-22 07:17:44.772 speecher[1897:707] * Terminating app due to
uncaught exception 'NSInternalInconsistencyException', reason:
'attempt to insert row 0 into section 0, but there are only 0 rows in
section 0 after the update'
The full code for that class, (the main MasterViewController class) is as follows.
//
// SpeecherMasterViewController.m
// speecher
//
//
#import "SpeecherMasterViewController.h"
#import "SpeecherDataController.h"
#import "SpeecherDetailViewController.h"
#interface SpeecherMasterViewController () {
NSString *newTitle;
NSMutableArray *_speeches;
NSMutableArray *_content;
SpeecherDataController *object;
}
#end
#implementation SpeecherMasterViewController
#synthesize detailViewController = _detailViewController;
- (void)awakeFromNib
{
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.detailViewController = (SpeecherDetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
object = [[SpeecherDataController alloc] init];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [object returnNoObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.textLabel.text = [object returnTitle:indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_speeches removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject: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.
}
}
/*
// 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;
}
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *titleobj = [object returnTitle:indexPath.row];
NSString *contentobj = [object returnContent:indexPath.row];
self.detailViewController.detailItem = titleobj;
self.detailViewController.detaitContent = contentobj;
}
- (void)insertNewObject:(id)sender
{
//Make sure clear before we start, also make sure initalized (double redundancy with clear statement at end)
newTitle = #"";
//New Title pop up UIAlert View
UIAlertView * alert = [[UIAlertView alloc]
initWithTitle:#"New Speech"
message:#"Please enter a name for speech"
delegate:self
cancelButtonTitle:#"Create"
otherButtonTitles:nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
UITextField * alertTextField = [alert textFieldAtIndex:0];
alertTextField.keyboardType = UIKeyboardTypeDefault;
alertTextField.placeholder = #"Enter a new title";
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
newTitle = [[alertView textFieldAtIndex:0] text];
[object addNewContent:newTitle :#"IT REALLY WORKS!" :#"Nothing"];
//create new speech title, add to array and add to tableview
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
//Clear newTitle for use next time
newTitle = #"";
}
#end
EDIT:
Amended to add [object addNewContent] method & class as per comments,
//
// SpeecherDataController.m
// speecher
//
//
#import "SpeecherDataController.h"
#interface SpeecherDataController ()
{
NSMutableArray *titles;
NSMutableArray *content;
NSMutableArray *timer;
}
#end
#implementation SpeecherDataController
-(void) addNewContent:(NSString*)sTitle : (NSString*)sContent :(NSString*)sTimer
{
[titles insertObject:sTitle atIndex:0];
[content insertObject:sContent atIndex:0];
[timer insertObject:sTimer atIndex:0];
}
//Methods to return data
-(NSString*) returnTitle:(NSUInteger)row
{
return [titles objectAtIndex:row];
}
-(NSString*) returnContent:(NSUInteger)row
{
return [content objectAtIndex:row];
}
-(NSString*) returnTimer:(NSUInteger)row
{
return [timer objectAtIndex:row];
}
-(NSInteger) returnNoObjects
{
return titles.count;
}
#end
The problem is the NSMutableArrays hadn't been alloc and init. Had to add a check to see if they had a init and alloc if not. New check looks like this,
-(void) addNewContent:(NSString*)sTitle : (NSString*)sContent :(NSString*)sTimer
{
if(!titles)
{
titles = [[NSMutableArray alloc] init];
}
if(!content)
{
content = [[NSMutableArray alloc] init];
}
if(!timer)
{
timer = [[NSMutableArray alloc] init];
}
[titles insertObject:sTitle atIndex:0];
[content insertObject:sContent atIndex:0];
[timer insertObject:sTimer atIndex:0];
}

Resources