I have 2 view controllers-1 for entering the value from the user and another to display value in a table view. The coding goes as follows:
This is for displaying the value passed by the notification:
ListTableViewContrller.m
#property(strong,nonatomic)NSMutableArray *namearray;
#end
#implementation ListTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(receieveTestNotificatiom:) name:#"TestNotification" object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)receieveTestNotificatiom:(NSNotification *)notification
{
_namearray=[[NSMutableArray alloc]initWithObjects:[notification.userInfo objectForKey:#"USERNAME"], nil];
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _namearray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellreuse" forIndexPath:indexPath];
cell.detailTextLabel.text=[_namearray objectAtIndex:indexPath.row];
return cell;
}
This is for entering the data from the user in a view controller named as source.m-
- (IBAction)senddata:(id)sender
{
NSDictionary *dict=[NSDictionary dictionaryWithObject:_nametextfield.text forKey:#"USERNAME"];
[[NSNotificationCenter defaultCenter]postNotificationName:#"TestNotification" object:nil userInfo:dict];
}
When i try to run my application, it is not displaying the entered value in the table view controller. Why is it so? Thanks in advance......
do like and try this
- (void)viewDidLoad {
[super viewDidLoad];
// allocate the memory here
_namearray=[NSMutableArray new];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(receieveTestNotificatiom:) name:#"TestNotification" object:nil];
}
-(void)receieveTestNotificatiom:(NSNotification *)notification
{
NSString *value = [NSString stringwithFormat:#"%#",[notification.userInfo objectForKey:#"USERNAME"]];
NSLog(#"%# value", [notification userInfo]);
[_namearray addobject:value];
[self.tableView reloadData];
}
your code looks ok. but do you really want to reinstantiate the array every time you receive a notification? or do you want to instantiate the array only once and then add values you get via notification? if the last is what you want here is my solution:
receiving tableviewcontroller
#interface TableViewController ()
#property (strong, nonatomic) NSMutableArray *names;
#end
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 44.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"NEW_NAME_NOTIFICATION" object:nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.names.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"NameCell" forIndexPath:indexPath];
cell.textLabel.text = self.names[indexPath.row];
return cell;
}
- (void)receivedNotification:(NSNotification *)notification {
[self.names addObject:notification.userInfo[#"value"]];
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:self.names.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
}
- (NSMutableArray *)names {
if (!_names) {
_names = [NSMutableArray array];
}
return _names;
}
#end
viewcontroller that posts notifications
#interface NewNameViewController ()
#property (weak, nonatomic) IBOutlet UITextField *textField;
#end
#implementation NewNameViewController
- (IBAction)doneBarButtonItemTapped:(UIBarButtonItem *)sender {
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"NEW_NAME_NOTIFICATION" object:nil userInfo:#{#"value": self.textField.text}];
}];
}
#end
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 am totally new in iOS developing. I am learning this on my own. I am now a little bit confused about what is notification centre. I have searched through web and studied about nsnotification centre.
I am posting this question just because to clarify my idea about nsnotificationcentre.
I am building a project where I have taken four view controllers. The name of the first view controller is default as it is. Now I have named the second view controller as country scene, the third view controller as state scene and the fourth one as city scene.
In country scene I have a table view where I am showing a list of 10 countries. Now when I am tapping on cells it goes to the state scene where I have taken a table view and there I am showing a list of 10 states and when I am tapping on any cells it goes to city scene where I have taken a table view and showing a list of 10 cities.
Now on my first view controller, I have two text fields. One is for choosing countries and one is for choosing cities.
I have chosen the countries using delegates. Now I want to choose cities.
Choosing cities will go like,
Home view controller ---> Country view controller ---> State view controller ---> City view controller. Then the cell where I tap that data will show in the city textfield of my home view controller.
Can any one please tell me how can I do this with nsnotificationcenter?
This is my Home View Controller implementation file
#import "ViewController.h"
#import "CountryViewController.h"
#interface ViewController ()<countryDelegate>
{
BOOL fromCountry;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.txtCity.delegate = self;
self.txtCountry.delegate = self;
self.txtCountry.text = self.strname;
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(updateCityName:) name:#"Updated City Name" object:nil];
}
-(void)updateCity:(NSString *)city
{
self.txtCity.text = city;
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"Updated City Name" object:nil];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if (textField.tag == 1) {
fromCountry=YES;
}
else{
[self performSegueWithIdentifier:#"countryScene" sender:self];
}
return YES;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
[_txtCountry resignFirstResponder];
CountryViewController *detailObject = (CountryViewController *) segue.destinationViewController;
detailObject.delegate=self;
detailObject.isFromCountry = fromCountry;
}
-(void)updateCountry:(NSString *)country
{
_txtCountry.text=country;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)countryButtonClicked:(id)sender {
fromCountry=YES;
[self performSegueWithIdentifier:#"countryScene" sender:self];
}
#end
This is my Country Scene implementation file
#import "CountryViewController.h"
#import "StateViewController.h"
#import "ViewController.h"
#interface CountryViewController ()
#property (nonatomic) NSString *lastSelectedCountryName;
#end
#implementation CountryViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.arrCountries = #[#"India", #"Bangladesh", #"Australia", #"New Zealand", #"South Africa", #"West Indies", #"Sri Lanka", #"England", #"Argentina", #"Brazil"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"countryCell"];
UILabel *lblCountry = (UILabel*)[cell.contentView viewWithTag:3];
lblCountry.text = [self.arrCountries objectAtIndex:indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrCountries count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_isFromCountry) {
if ([self.delegate respondsToSelector:#selector(updateCountry:)])
{
[self.delegate updateCountry:[_arrCountries objectAtIndex:indexPath.row]];
}
[self.navigationController popViewControllerAnimated:YES];
}
else
[self performSegueWithIdentifier: #"stateScene" sender: self];
}
#end
This is my State Scene implementation file
#import "StateViewController.h"
#interface StateViewController ()
#end
#implementation StateViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.arrStates = #[#"West Bengal", #"Uttar Pradesh", #"Madhya Pradesh", #"Jharkhand", #"Bihar", #"Tamilnadu", #"Myanmar", #"Arunachal Pradesh", #"Assam", #"Goa"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"stateCell"];
UILabel *lblStates = (UILabel*)[cell.contentView viewWithTag:4];
lblStates.text = [self.arrStates objectAtIndex:indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrStates count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier: #"cityScene" sender: self];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is my City Scene implementation file
#import "CityViewController.h"
#interface CityViewController ()
#end
#implementation CityViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.arrCities = #[#"Kolkata", #"Bangalore", #"Chennai", #"Mumbai", #"Hyderabad", #"Mangalore", #"New York", #"London", #"Rio de Janeiro", #"Buenos Aires"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cityCell"];
UILabel *lblCities = (UILabel*)[cell.contentView viewWithTag:5];
lblCities.text = [self.arrCities objectAtIndex:indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrCities count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Updated City Name" object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Well in your city scene you have to pass the city name as the object in the notification and then you have to get object in your first view controller i.e. ViewController
So in your city scene, do like this
[[NSNotificationCenter defaultCenter]postNotificationName:#"Updated City Name" object:[self.arrCities objectAtIndex:indexPath.row]];
Now in your first ViewContrller where you have text fields, do like this
Add the observer in your viewDidLoad: method
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(updateCity:) name:#"Updated City Name" object:nil];
Now implement the method
- (void)updateCity:(NSNotification *)notification {
NSString *cityName = notification.object;
self.txtCity.text = cityName;
}
I'm seeing some strange behaviour with my UItableViewController shown using Popover.
This is my ViewController code:
#interface PrepareViewController ()
{
NSMutableArray *_objects;
NSString *savingKey;
}
#end
#implementation PrepareViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)awakeFromNib
{
self.clearsSelectionOnViewWillAppear = NO;
self.preferredContentSize = CGSizeMake(320.0, 600.0);
[super awakeFromNib];
}
- (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.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"];
// Setup savingKey
savingKey = #"prepareKey";
// Load the items from NSUserDefaults
_objects = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:savingKey]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(defaultsChanged:) name:NSUserDefaultsDidChangeNotification object:nil];
}
- (void)defaultsChanged:(NSNotification *)notification {
// Setup savingKey
savingKey = #"prepareKey";
// Load the items from NSUserDefaults
_objects = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:savingKey]];
// Reload the tableView
[self.tableView reloadData];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)saveSummaries {
// Save the summaries to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:_objects forKey:savingKey];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
#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 _objects.count;
}
// 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;
}
- (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 didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Open the chosen item
MyManager *sharedManager = [MyManager sharedManager];
sharedManager.openSummary = _objects[indexPath.row];
// Modal to SummaryViewController
[self performSegueWithIdentifier:#"summarySegue" sender:self];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_objects removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Delete the associated information
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:#"%#%#", _objects[indexPath.row], #"-summary"]];
NSLog(#"delete3");
// Save the new list of combined summaries
[[NSUserDefaults standardUserDefaults] setObject:_objects forKey:#"prepareKey"];
} 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.
}
}
#end
Problem:
When the user taps delete while in edit mode, no animation appears and the selected item snaps back into place without any animation and the item remains undeleted. I've checked that the delete method gets called - any idea what could be the problem?
Thanks for help!
I think it's because of this:
- (void)defaultsChanged:(NSNotification *)notification {
// Setup savingKey
savingKey = #"prepareKey";
// Load the items from NSUserDefaults
_objects = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:savingKey]];
// Reload the tableView
[self.tableView reloadData]; <------- manual reload without animations
}
When you change defaults in:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
that code is executed.
I create a UITableViewController using storyboard, and want to reload the tableview every time it detect a device(for bonjour protocol).
However, the reload data method only calls numberofRows, but not call CellForRowatIndexPath. So I have nothing changed. The mutablearray I checked is always going correctly. NewObjects are added. But the tableview doesn't change with the array. So I am wondering if I set sth wrong here.
From the NSLog I added, I found, I could load the tableview at the beginning with
the initialized array
self.serviceArray = [[NSMutableArray alloc]initWithObjects:#"test", nil];
But in the method
- (void)addService:(NSNetService *)....
Everytime I reload, the new object can be added to the mutableArray, but the tableview doesn't change with the array. (It called the numberOfRows, and I check the array size returned is not 0, but then it doesn't call the cellOfRowAtIndex)
Here is my code
.h file
#import <UIKit/UIKit.h>
#import "Server.h"
#interface BrowserViewController : UITableViewController <ServerDelegate>
{
Server *_server;
NSMutableArray *_serviceArray;
}
#property (retain,nonatomic) NSMutableArray *serviceArray;
#property (nonatomic,retain) Server *server;
- (void)addService:(NSNetService *)service moreComing:(BOOL)more;
#end
.m file
#import "BrowserViewController.h"
#implementation BrowserViewController
#synthesize serviceArray = _serviceArray;
#synthesize server = _server;
- (void) dealloc
{
[self.serviceArray release];
[self.tableView release];
[super dealloc];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
self.title = #"Service Browser";
_serviceArray = nil;
self.serviceArray = nil;
[self.tableView setDelegate: self];
[self.tableView setDataSource:self];
//actually I set this in the storyboard already
[self.tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
_serviceArray = nil;
NSLog(#"viewwilldisappear");
}
- (NSMutableArray *)serviceArray {
if(nil == _serviceArray) {
self.serviceArray = [[NSMutableArray alloc]initWithObjects:#"test", nil];
}
else
{
NSLog(#"update array");
}
return _serviceArray;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)addService:(NSNetService *)service moreComing:(BOOL)more{
[self.serviceArray addObject:service];
if (!more) {
[self.tableView reloadData];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Connection Choices";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.serviceArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *Cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (Cell == nil) {
Cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
}
NSString *text = [self.serviceArray objectAtIndex:indexPath.row];
Cell.textLabel.text = text;
return Cell;
}
#end
I checked some solution, it's either delegate setting problem, or the array is null. or cell initialized without space. Is there any way to check what's the delegate of some method ?
I also tried to create a tableview property in the .h file, linked IBOutlet, then synthesize it in the .m. But still doesn't work. Could anyone help me?
Since a lot of tutorials are based on window-based application, could someone maybe provide me some tutorial using storyboard and using reloadData ? I could check if the Outlets are wrong.
Thanks in advance.
UPDATE1
AddService method is called in the appDelegate
appDelegate.h
#import <UIKit/UIKit.h>
#import "Server.h"
#class BrowserViewController;
#interface iphoneNetworkAppDelegate : NSObject <UIApplicationDelegate,UITableViewDataSource, UITableViewDelegate, ServerDelegate>
{
Server *_server;
UIWindow *window;
IBOutlet BrowserViewController *BrowserVC;
}
#property (strong, nonatomic) UIWindow *window;
#end
appDelegate.m
#import "iphoneNetworkAppDelegate.h"
#import "BrowserViewController.h"
#implementation iphoneNetworkAppDelegate
#synthesize window;
- (void)dealloc
{
[window release];
[_server release];
_server = nil;
[BrowserVC release];
BrowserVC = nil;
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *type = #"TestingProtocol";
_server = [[Server alloc] initWithProtocol:type];
_server.delegate = self;
NSError *error = nil;
if(![_server start:&error]) {
NSLog(#"error = %#", error);
}
BrowserVC = [BrowserViewController alloc];
if (BrowserVC == nil) {
NSLog(#"need to init");
}
BrowserVC.server = _server;
return YES;
}
#pragma mark Server Delegate Methods
- (void)serverRemoteConnectionComplete:(Server *)server {
NSLog(#"Server Started");
BrowserVC.server = server;
}
- (void)serverStopped:(Server *)server {
NSLog(#"Server stopped");
}
- (void)server:(Server *)server didNotStart:(NSDictionary *)errorDict {
NSLog(#"Server did not start %#", errorDict);
}
- (void)server:(Server *)server didAcceptData:(NSData *)data {
NSLog(#"Server did accept data %#", data);
}
- (void)server:(Server *)server lostConnection:(NSDictionary *)errorDict {
NSLog(#"Server lost connection %#", errorDict);
}
- (void)serviceAdded:(NSNetService *)service moreComing:(BOOL)more {
NSLog(#"service added in delegate");
[BrowserVC addService:service moreComing:more];
}
#pragma mark -
- (void)applicationWillTerminate:(UIApplication *)application {
[_server stop];
[_server stopBrowser];
}
If the appDelegate setting is like this, reloadData cannot be called ?
Please check this terms may help you:
self.tableView is object bind in TableView in XIB.
Included <UITableViewDelegate,UITableViewDataSource> delegates in .h file?
Properly set getter setter your object "self.tableView"
Delegate set?
a)[self.tableView setDelegate: self];
b)[self.tableView setDataSource:self];
i think No need for the following lines in view will appear
_serviceArray = nil;
self.serviceArray = nil;
And also makes sure that the function addService got called:
I use the following method to present a UIViewController named DictAddSubSecondCell:
// UIViewControler 1
- (IBAction)addWord:(id)sender{
dictAddSubSecondCellController = [[DictAddSubSecondCell alloc] initWithNibName:#"DictAddSubSecondCell" bundle:nil];
[self presentModalViewController:dictAddSubSecondCellController animated:YES];
[dictAddSubSecondCellController release];
}
and when I click the button in DictAddSubSecondCell:
- (IBAction)dismissAction:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
the tableView at UIViewControler 1 didn't reload it's data, but I added a method in viewWillApear method:
[self.table reloadData];
but it still not work. I have no idea about this. Is there any suggestions for me? thanks.
Here is the full source code of UIViewcontroller 1:
//
// DictAddSubSecond.m
//
// Created by Samuel Armstrong on 4/8/12.
// Copyright 2012 __MyCompanyName__. All rights reserved.
//
#import "DictAddSubSecond.h"
#import "DictionaryList.h"
#implementation DictAddSubSecond
#synthesize dictList, table, editButton;
#synthesize dictAddSubSecondCellController;
- (IBAction)addWord:(id)sender
{
dictAddSubSecondCellController = [[DictAddSubSecondCell alloc] initWithNibName:#"DictAddSubSecondCell" bundle:nil];
[self presentModalViewController:dictAddSubSecondCellController animated:YES];
[dictAddSubSecondCellController release];
}
- (IBAction)toggleEdit {
[self.table setEditing:!self.table.editing animated:YES];
if (self.table.editing) {
[editButton setTitle:#"Done"];
[editButton setStyle:UIBarButtonItemStyleDone];
}
else {
[editButton setTitle:#"Edit"];
[editButton setStyle:UIBarButtonItemStyleBordered];
}
}
- (IBAction)dismissAction:(id)sender
{
[self dismissModalViewControllerAnimated:NO];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)refreshTableData
{
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *file = [path stringByAppendingPathComponent:#"dictWithWords.tmp"];
if (dictList == nil) {
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:file];
if ([array objectAtIndex:0] != nil) {
dictList = [[NSMutableArray alloc] initWithCapacity:1];
self.dictList = array;
[array release];
}
else
{
dictList = [[NSMutableArray alloc] initWithCapacity:1];
}
}
[self.table reloadData];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self refreshTableData];
}
- (void)someMethodToReloadTable:(NSNotification *)notification
{
[table reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(someMethodToReloadTable) name:#"reloadTable" object:nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"reloadTable" object:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dictList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MoveMeCellIdentifier = #"MoveMeCellIdentifier";
UITableViewCell *cell = [self.table dequeueReusableCellWithIdentifier:MoveMeCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MoveMeCellIdentifier] autorelease];
//A Boolean value that determines whether the cell shows the reordering control.
cell.showsReorderControl = YES;
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [dictList objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark -
#pragma mark Table View Delegate Methods
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
[self.dictList removeObjectAtIndex:row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationMiddle];
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
// Asks the data source whether a given row can be moved to another location in the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
//Tells the data source to move a row at a specific location in the table view to another location.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSUInteger fromRow = [fromIndexPath row];
NSUInteger toRow = [toIndexPath row];
id object = [[dictList objectAtIndex:fromRow] retain];
[dictList removeObjectAtIndex:fromRow];
[dictList insertObject:object atIndex:toRow];
[object release];
}
#end
Try calling it in viewDidAppear: instead of viewWillAppear:.