I have a viewcontroller set up on my storyboard, and I have inserted a tableView inside this view controller. I want to do a [self.tableView reloadData].
This is what my viewController.m looks like. My tableView is an IBOutlet called sharedView, hence the names in the methods, but I am doing something wrong as on viewDidLoad when I call configureView, and subsequently [self.sharedView reloadData]; the data doesn't show up inside the table.
#import "DetailViewController.h"
#import "sharedUsersTable.h"
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [[self.detailItem objectForKey:#"lock_name"] description];
activeUsers = [self.detailItem objectForKey:#"active_shared_users"];
[self.sharedView reloadData];
//NSLog(#"Info: %#", activeUsers);
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSString *)sharedView:(UITableView *)sharedView titleForHeaderInSection:(NSInteger)section {
return #"Shared with";
}
- (NSInteger)sharedView:(UITableView *)sharedView numberOfRowsInSection:(NSInteger)section
{
return activeUsers.count;
}
- (sharedUsersTable *)sharedView:(UITableView *)sharedView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"sharedUser";
sharedUsersTable *cell = [sharedView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[sharedUsersTable alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *key;
NSString *name;
NSString *email;
// NSString *permission;
key = [activeUsers objectAtIndex:indexPath.row];
name = [key objectForKey:#"shared_user_name"];
email = [key objectForKey:#"email"];
NSLog(#"Info: %#", name);
cell.textLabel.text = [NSString stringWithFormat:#"%#", name];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", email];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
#end
You should add info about protocols that Your VC is implementing:
#interface DetailViewController () <UITableViewDataSource, UITableViewDelegate>
- (void)configureView;
#end
and then:
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [[self.detailItem objectForKey:#"lock_name"] description];
activeUsers = [self.detailItem objectForKey:#"active_shared_users"];
/* I assume that Your table view is self.sharedView though You should change the name and I assume that it is connected to VC */
self.sharedView.dataSource = self;
self.sharedView.delegate = self;
[self.sharedView reloadData];
//NSLog(#"Info: %#", activeUsers);
}
}
You can also set data source and delegate directly in storyboard - I think that You have to ctrl+drag from table view to vc. Sorry if this is not correct - I do not use IB for quite some time no - only code.
And one more thing - read this:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UITableViewDataSource
And change method names to be exactly the same as in the protocol - If You do not It won't work.
For better undesstanding data sources and delegates try:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/tableview_iphone/CreateConfigureTableView/CreateConfigureTableView.html
You mentioned that you are using a UIViewController and not UITableViewController. If you are using UIViewController then you will need to implement UITableViewDelegate and UITableViewDataSourceDelegate. You will also need to connect those delegates either through code or using the interface builder or Storyboard.
Related
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
I have two UIViews in my app.
in first view there is a tableveiw with two cells(to select city and country). when user select first cell(to select city), then it goes to anothrview that has a list of cities. then when user select a city(select a tableviecell text), the selected should display in firtview's tableviewcell text.
this is my code in secondview controller(it is a tableview Controller).
- (void)viewDidLoad {
[super viewDidLoad];
detailFlights = #[#"colombo1",#"colombo2",#"colombo3",#"colombo14",#"colombo15",#"colombo16",#"colombo17"];
// 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)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [detailFlights count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"identi" forIndexPath:indexPath];
cell.textLabel.text = [detailFlights objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
This kind of problem is solved using the delegate pattern. A pattern widely used in iOS programming. See this question if you don't know how it works.
As deadbeef said, you must implement delegate method to transfer data to first view, but logic for that is to choose objectAtIndex of indexPath.row in didSelect: [detailFlights objectAtIndex:indexPath.row];
As an alternative to the delegate method that others have mentioned, you can use an unwind segue to pass data back to the previous view controller.
Unwind segues give you a way to "unwind" the navigation stack back through push, modal, popover, and other types of segues. You use unwind segues to "go back" one or more steps in your navigation hierarchy. Unlike a normal segue, which create a new instance of their destination view controller and transitions to it, an unwind segue transitions to an existing view controller in your navigation hierarchy. Callbacks are provided to both the source and destination view controller before the transition begins. You can use these callbacks to pass data between the view controllers.
Here's a example where the second (source) view controller presented a list of fonts, and the first (destination) view controller updates its table row to show the selected font:
- (IBAction)unwindFromFontPreference:(UIStoryboardSegue *)segue
{
FontTableViewController *fontTableViewController = segue.sourceViewController;
if (self.currentFontSelection != fontTableViewController.currentFontSelection)
{
self.currentFontSelection = fontTableViewController.currentFontSelection;
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:0 inSection:LALSettingsTableViewSectionFont]]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()<UITableViewDelegate, UITableViewDataSource, ViewControllerDelegate>
#property (nonatomic, retain) NSMutableArray* data;
#property (nonatomic, retain) IBOutlet UITableView* tableView;
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.data = [NSMutableArray array];
[self.data addObject:#"country"];
[self.data addObject:#"city"];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSString* text = [self.data objectAtIndex:indexPath.row];
cell.textLabel.text = text;
return cell;
}
-(void) updateText:(NSString *)text
{
[self.data replaceObjectAtIndex:1 withObject:text];
[self.tableView reloadData];
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"secondView"])
{
UINavigationController* controller = [segue destinationViewController];
NSArray *viewControllers = controller.viewControllers;
SecondViewController* viewController = [viewControllers objectAtIndex:0];
viewController.delegate = self;
}
}
SecondViewController.h
#import <UIKit/UIKit.h>
#protocol ViewControllerDelegate <NSObject>
-(void) updateText:(NSString*)text;
#end
#interface SecondViewController : UIViewController
#property (nonatomic, assign) id<ViewControllerDelegate> delegate;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#property(nonatomic ,retain) NSArray* detailFlights;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.detailFlights = #[#"colombo1",#"colombo2",#"colombo3",#"colombo14",#"colombo15",#"colombo16",#"colombo17"];
// 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)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.detailFlights count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = [self.detailFlights objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{ NSString* text = [self.detailFlights objectAtIndex:indexPath.row];
[self.delegate updateText:text];
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
whole project is here
In didDeselectRowAtIndexPath method you can get that string using following way
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *selectedString = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
}
now save to pass previous view controller you can store it in UserDefaults OR
make a property in previousViewController and before go back set it value like follow
if you are using navigationController then
ViewController *previousViewController = (ViewController *) self.navigationController.viewControllers[self.navigationController.viewControllers.count-2];
previousViewController.selectedString = selectedString;
or
you can also use block for passing data. example of block
I have a UITableView with custom table view cell.
That cell has a custom delete button. Button action is within the cell class.
I can't reload the table from cell class after deleted row from db. If I try to get table view from cell.superview or cell.superview.superview, the app crashes.
This is cell implementation
#implementation pixSavedTableViewCell
- (IBAction)deleteBusiness:(id)sender {
NSLog(#"DELETING BUSINESS cell");
self.hidden=YES;
pixDBManager *dbConnection = [[pixDBManager alloc]init];
dbConnection.businessName = self.nameLable.text;
[dbConnection deleteBusiness];
//[(UITableView *)self.superview.superview reloadData];
}
#end
This will delete data from
-(void)deleteBusiness
{
NSLog(#"DELETING BUSINESS");
char *error;
if(sqlite3_open([dbPathString UTF8String], &businessDB)==SQLITE_OK){
NSString *deleteStatement = [NSString stringWithFormat:#"DELETE FROM SAVEDBUSINESS WHERE 'NAME'='%#'",_businessName];
const char *delete_stmt = [deleteStatement UTF8String];
NSLog(#"%s",delete_stmt);
if (sqlite3_exec(businessDB, delete_stmt, NULL, NULL, &error)==SQLITE_OK) {
NSLog(#"Business Deleted");
}
else{
NSLog(#"Cant Delete Data");
}
sqlite3_close(businessDB);
}
else{
NSLog(#"Cant Open Data Base");
}
}
This is my view controller implementation
#implementation pixSavedViewController
{
NSMutableArray *businessArray;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
pixDBManager *dbConnection = [[pixDBManager alloc]init];
businessArray = [[NSMutableArray alloc]init];
[dbConnection createOrOpenDB];
businessArray = [dbConnection getSavedBusiness];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return businessArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *customcellidentifier = #"CustomCell3";
pixSavedTableViewCell *cell = (pixSavedTableViewCell *)[tableView dequeueReusableCellWithIdentifier:customcellidentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"Savedcell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
pixBusinessDetails *details = [[pixBusinessDetails alloc]init];
details = [businessArray objectAtIndex:indexPath.row];
cell.nameLable.text = details.name;
cell.addressLable.text = details.address;
cell.descriptionLable.text = details.description;
cell.scoreLable.text = details.score;
cell.votesLable.text = details.votes;
NSLog(#"Business Detail %#\n %#\n %#\n %#\n %#\n %#\n",details.name, details.address,details.description,details.score,details.votes,details.imageId);
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 130;
}
Rather than deleting the data from within the UITableViewCell, you should instead call a method in your UIViewController which will delete the data and then reload the table.
On way to do this is to create a protocol for your UIViewController to conform to:
#protocol pixSavedTableViewCellDelegate
- (void)deleteBuisness:(NSString *) businessName
#end
#interface pixSavedTableViewCell : UITableViewCell
#property (nonatomic, weak) id<pixSavedTableViewCellDelegate> delegate;
#end
Then in you UITableViewCell you change your delete method to:
- (IBAction)deleteBusiness:(id)sender {
[self.delegate deleteBuisness:self.nameLabel.text];
}
In your UIViewController you then implement the protocol:
#interface pixSavedViewController <pixSavedTableViewCellDelegate>
#end
#implementation pixSavedViewController
#pragma mark - pixSavedTableViewCellDelegate
- (void)deleteBuisness:(NSString *) businessName
{
pixDBManager *dbConnection = [[pixDBManager alloc]init];
dbConnection.businessName = businessName;
[dbConnection deleteBusiness];
[self.tableView reloadData];
}
You'll also need to set the delegate when creating the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//All your current code
cell.delegate = self;
return cell;
}
This is what the delegate pattern is for, in my opinion:
Make your UITableViewController a delegate of your custom cell.
MyCustomCell *cell = ....
cell.deleteDelegate = self
//in your UITableViewController
- (void)willDeleteCustomCell:(MyCustomCell*)cell
{
}
//on your cell
- (IBAction)deleteBusiness:(id)sender
{
[self.deleteDelegate willDeleteCustomCell:self];
//rest of your delete code
}
I'm going through the Apple Start Developing Guide and I have encountered an error in the demo app.
The code is as follows:
#import "XYZToDoListViewController.h"
#import "XYZToDoItem.h"
#interface XYZToDoListViewController ()
#property NSMutableArray *toDoItems;
-(void)viewDidLoad{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc]init];
[self loadInitialData];
}
#end
#implementation XYZToDoListViewController
-(void)loadInitialData{
XYZToDoItem *item1 = [[XYZToDoItem alloc]init];
item1.itemName = #"Buy Milk";
[self.toDoItems addObject:item1];
XYZToDoItem *item2 = [[XYZToDoItem alloc]init];
item2.itemName = #"Go Shopping";
[self.toDoItems addObject:item2];
XYZToDoItem *item3 = [[XYZToDoItem alloc]init];
item3.itemName = #"Wake Up";
[self.toDoItems addObject:item3];
}
- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 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)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 = #"ListPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.textLabel.text = toDoItem.itemName;
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
{
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
}
}
*/
/*
// 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 story board-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.
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
On building it comes up with an error saying it expected ; after viewDidLoad.
I have googled this to see if I can figure out why but can't seem to.
put this in your .h file
#interface className : Class that you inherit
#property NSMutableArray *toDoItems;
#end
of course, you'd need to replace className with your name for the class, and the 'Class that you inherit' with the super classes such as NSObject, UIViewController, UIView, or any other class.
and put this in your .m file
#implementation className
-(void)viewDidLoad{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc]init];
[self loadInitialData];
}
#end
that should help.
Hope it helps :)
It looks like you might either have the property:
#property NSMutableArray *toDoItems;
In the implementation file (.m) or the method:
-(void)viewDidLoad{
...
}
In the header file (.h).
In addition you'll need an #implementation or #interface. Maybe you should update your question with the full code from the file.
The below property should be in .h file. Because in .h file we need to declare the method so property will declare the method which should be in .h file
#property NSMutableArray *toDoItems;
And below will be in .m file because in .m file we need to define the method.
- (void)viewDidLoad
{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
}
I have 2 Controllers, 1 is to load data from JSON, the other is a simple UITableViewController. My problem is that the view is loaded before the data. How can I make the data load before my table? I'm new to Objective-C OOP :/
the code
#import "MasterViewController.h"
#import "DetailViewController.h"
#import "DealsDataController.h"
#import "Deals.h"
#implementation MasterViewController
- (void)awakeFromNib
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
}
[super awakeFromNib];
self.dataController = [[DealsDataController alloc] init];
NSLog(#"this is the awake from nib count %i",[self.dataController countOfList]);
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"did this count the list %i",[self.dataController countOfList]);
return [self.dataController countOfList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DealCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Deals *dealAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:dealAtIndex.name];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return NO;
}
/*
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_objects 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)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
NSDate *object = _objects[indexPath.row];
self.detailViewController.detailItem = object;
}
}
- (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
and the Data Controller
#import "DealsDataController.h"
#import "Deals.h"
#implementation DealsDataController
#synthesize masterDealsList = _masterDealsList;
-(id)init {
if (self = [super init]) {
[self initializeDataList];
return self;
}
return nil;
}
-(NSMutableArray *)masterDealsList {
if (!_masterDealsList) {
_masterDealsList = [[NSMutableArray alloc] init];
}
return _masterDealsList;
}
-(void)setMasterDealsList:(NSMutableArray *)newList {
if (_masterDealsList != newList) {
_masterDealsList = newList;
}
}
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
_deals = [json objectForKey:#"deals"]; //2
NSLog(#"deals: %#", _deals);
NSArray *dealName = [_deals valueForKey:#"deal_name"];
NSLog(#"deals Name: %#", dealName);
for (int i = 1;i <= [_deals count]; i++) {
NSDictionary* dict = [_deals objectAtIndex:i-1];
Deals *deal =[[Deals alloc] initWithProdID:1 name:[dict valueForKey:#"deal_name"] description:[dict objectForKey:#"deal_description"] price:10.00 specs:#"specs" terms:#"terms"];
[self addDealWithDeal:deal];
NSLog (#"masterListCount %i ", [self countOfList]);
}
}
-(void)initializeDataList {
//NSDate *today = [NSDate date];
dispatch_async(sweetDealsQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:sweetDealsURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
-(NSUInteger)countOfList {
return [self.masterDealsList count];
}
-(Deals *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.masterDealsList objectAtIndex:theIndex];
}
-(void)addDealWithDeal:(Deals *)deal {
[self.masterDealsList addObject:deal];
}
#end
In MVC, you'd typically have one view controller per view. So a single view controller would be responsible for everything display on one view. Of course, you can have helper classes, or use sub view controllers (e.g. widgets), or if you're developing for iPad, you might have two view controllers (one for the side menu, one for the main view).
I'd suggest you do the following
Make your DataController a subclass of NSObject instead of UIViewController. From what I understand, it is a data access class, not responsible for UI.
In the viewDidLoad method of your MasterViewController, allocate and initialise a DataController object and trigger its data load method.
Either set a callback so when data is fetched, a method on the MasterViewController is called with the data. Or set your MasterViewController as a delegate for your DataController and when it's done, assign the data to a property of the MasterViewController.
i guess you need to perform Data loading before initialising your TableViewController and as you get response Data load the TableViewController. for that refer this post how to wait until some method complete execution, perform data loading in that method.
Its okay to display a blank tableview with an activity indicator overlay while the data is loading. When the data has finished loading, you can just reload the tableview with the data and remove the activity indicator. [tableview reloaddata] would call all of the datasource delegate methods which would then have your data in it.