I have 3 textfields, a submit button and a table view in a view controller. Now I want to show the datas of the 3 text fields to 3 labels of a custom cell in my table view and when I again update the datas the updated datas should be shown in the next cell. But in my code the updated datas are showing in the cells. The previous datas are overwriting. SO can any one tell me where am I wrong?
This is my ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *addressTextField;
#property (weak, nonatomic) IBOutlet UITextField *phoneTextField;
- (IBAction)submitButton:(id)sender;
#property (weak, nonatomic) IBOutlet UITableView *detailTable;
#property(nonatomic, strong)NSMutableArray *arrPeopleDetail;
#end
This is my ViewController.m
#import "ViewController.h"
#import "detailObject.h"
#interface ViewController ()
#end
#implementation ViewController
{
detailObject *peopleDetail;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.arrPeopleDetail = [[NSMutableArray alloc]init];
peopleDetail = [[detailObject alloc]init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)submitButton:(id)sender {
[self.detailTable reloadData];
if ([self.nameTextField.text isEqualToString:#""] || [self.addressTextField.text isEqualToString:#""] || [self.phoneTextField.text isEqualToString:#""] ) {
UIAlertView *alrt = [[UIAlertView alloc]initWithTitle:#"Warning" message:#"Plaeas Enter Text In The Empty Field" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil ];
[alrt show];
}
else{
peopleDetail.strPeopleName = self.nameTextField.text;
peopleDetail.strPeopleAddress = self.addressTextField.text;
peopleDetail.strPeoplePhoneNumber = self.phoneTextField.text;
[self.arrPeopleDetail addObject:peopleDetail];
}
//[self.detailTable reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
UILabel *lbl1 = (UILabel*)[cell.contentView viewWithTag:1];
lbl1.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeopleName"];
UILabel *lbl2 = (UILabel*)[cell.contentView viewWithTag:2];
lbl2.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeopleAddress"];
UILabel *lbl3 = (UILabel*)[cell.contentView viewWithTag:3];
lbl3.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeoplePhoneNumber"];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrPeopleDetail count];
}
#end
This is the .h NSObject class that I have Taken.
#import <Foundation/Foundation.h>
#interface detailObject : NSObject
#property(nonatomic,strong) NSString *strPeopleName;
#property(nonatomic,strong) NSString *strPeopleAddress;
#property(nonatomic,strong) NSString *strPeoplePhoneNumber;
#end
Add line peopleDetail = [[detailObject alloc]init]; in else case of submitButton action and after adding the new object into array reload table view data
i.e.
else{
peopleDetail = [[detailObject alloc]init];
peopleDetail.strPeopleName = self.nameTextField.text;
peopleDetail.strPeopleAddress = self.addressTextField.text;
peopleDetail.strPeoplePhoneNumber = self.phoneTextField.text;
[self.arrPeopleDetail addObject:peopleDetail];
[self.detailTable reloadData];
}
You can remove the peopleDetail = [[detailObject alloc]init]; from viewDidLoad
I realised where I was wrong. I was creating the object globally instead of creating it locally. If anyone does this mistake what happens is, every time when user enters data the datas are being overwritten because the created object is one. So the main mistake was creating the object globally instead of creating it locally.
So the updated ViewController.m is..
#import "ViewController.h"
#import "detailObject.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.arrPeopleDetail = [[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)submitButton:(id)sender {
if ([self.phoneTextField.text isEqualToString:#""] && [self.addressTextField.text isEqualToString:#""] && [self.phoneTextField.text isEqualToString:#""] ) {
UIAlertView *alrt = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Please Fillup The Above Fields" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alrt show];
}
else if ([self.nameTextField.text isEqualToString:#""]) {
UIAlertView *alrt_name = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Plaeas Enter Name" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil ];
[alrt_name show];
}
else if ([self.addressTextField.text isEqualToString:#""]) {
UIAlertView *alrt_address = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Please Enter Address" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alrt_address show];
}
else if ([self.phoneTextField.text isEqualToString:#""]) {
UIAlertView *alrt_phoneNumber = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Please Enter Phone Number" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alrt_phoneNumber show];
}
else
{
detailObject *peopleDetail = [[detailObject alloc] init];
peopleDetail.strPeopleName = self.nameTextField.text;
peopleDetail.strPeopleAddress = self.addressTextField.text;
peopleDetail.strPeoplePhoneNumber = self.phoneTextField.text;
[self.arrPeopleDetail addObject:peopleDetail];
self.nameTextField.text = #"";
self.addressTextField.text = #"";
self.phoneTextField.text = #"";
}
[self.detailTable reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
UILabel *lbl1 = (UILabel*)[cell.contentView viewWithTag:1];
lbl1.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeopleName"];
UILabel *lbl2 = (UILabel*)[cell.contentView viewWithTag:2];
lbl2.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeopleAddress"];
UILabel *lbl3 = (UILabel*)[cell.contentView viewWithTag:3];
lbl3.text = [[self.arrPeopleDetail objectAtIndex:indexPath.row]valueForKey:#"strPeoplePhoneNumber"];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrPeopleDetail count];
}
#end
Related
I have created a customTableCell class that serves as a formatter for the construction of the UITableView in my FirstViewController. The code for all relevant classes will be provided below.
What I am attempting to do:
I am attempting to change the value of the regularBubbleCostLabel which is a property of the customTableCell class. The problem that I am having is that I cannot reference a specific cell that has been displayed in the UITableView.
How can I create references to each of the customTableCells that are being displayed in the UITableView?
customTableCell.h
#import <UIKit/UIKit.h>
#interface customTableCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIImageView *primaryImageView;
#property (strong, nonatomic) IBOutlet UILabel *upgradeNameLabel;
#property (strong, nonatomic) IBOutlet UILabel *descriptionLabel;
#property (strong, nonatomic) IBOutlet UIImageView *regularCurrencyIcon;
#property (strong, nonatomic) IBOutlet UILabel *regularBubbleCostLabel;
#end
customTableCell.m
#import "customTableCell.h"
#implementation customTableCell
#synthesize primaryImageView = _primaryImageView;
#synthesize upgradeNameLabel = _upgradeNameLabel;
#synthesize descriptionLabel = _descriptionLabel;
#synthesize regularBubbleCostLabel = _regularBubbleCostLabel;
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "RWGameData.h"
#import "customTableCell.h"
#interface FirstViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UILabel *regularBubbleLabel;
#property (strong, nonatomic) IBOutlet UILabel *premiumBubbleLabel;
#property (strong, nonatomic) IBOutlet UIImageView *regularBubbleIcon;
#property (strong, nonatomic) IBOutlet UIImageView *premiumBubbleIcon;
#property (strong, nonatomic) IBOutlet UINavigationBar *navBar;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
{
NSArray *upgrades;
NSArray *thumbnails;
NSArray *descriptions;
NSArray *megaBubbleUpgradeFees;
NSInteger rowID;
NSInteger cellCount;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Upgrades" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
upgrades = [dict objectForKey:#"UpgradeStrings"];
thumbnails = [dict objectForKey:#"UpgradeImages"];
descriptions = [dict objectForKey:#"UpgradeDescriptions"];
megaBubbleUpgradeFees = [dict objectForKey:#"MegaBubbleUpgradeFee"];
_regularBubbleLabel.text = [NSString stringWithFormat:#"%li", [RWGameData sharedGameData].regularBubbleCount];
_premiumBubbleLabel.text = [NSString stringWithFormat:#"%li", [RWGameData sharedGameData].premiumBubbleCount];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [upgrades count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Handles appearance of cells in table.
static NSString *TableIdentifier = #"TableCell";
//customTableCell *cell = (customTableCell *)[tableView dequeueReusableCellWithIdentifier:TableIdentifier];
customTableCell *cell = (customTableCell *)[tableView dequeueReusableCellWithIdentifier:TableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"customTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.primaryImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.upgradeNameLabel.text = [upgrades objectAtIndex:indexPath.row];
cell.descriptionLabel.text = [descriptions objectAtIndex:indexPath.row];
cell.regularCurrencyIcon.image = [UIImage imageNamed:#"megaBubbleLarge30.png"];
cell.regularBubbleCostLabel.text = [NSString stringWithFormat:#"%#", megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
rowID = indexPath.row;
[self makePayment:self];
}
- (IBAction)makePayment:(id)sender {
UIAlertView *messageAlert;
if (rowID == 0) {
if ([RWGameData sharedGameData].regularBubbleCount >= [megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier] intValue]) {
//NSLog(#"Balance: %li | Cost: %# |-> Sufficient amount!", [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
if ([RWGameData sharedGameData].megaBubblePopValue <= 1) {
[RWGameData sharedGameData].megaBubblePopValue++;
} else {
[RWGameData sharedGameData].megaBubblePopValue *= 2;
}
[[RWGameData sharedGameData] save];
NSLog(#"New Pop Value: %i", [RWGameData sharedGameData].megaBubblePopValue);
} else {
messageAlert = [[UIAlertView alloc] initWithTitle:#"Not enough bubbles!!" message:#"You need to collect more bubbles or purchase them from our store!" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Buy", nil]; [messageAlert show];
} NSLog(#"Cell ID: %li | Balance: %li | Cost: %#", rowID, [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else if (rowID == 1) {
if ([RWGameData sharedGameData].regularBubbleCount >= [megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier] intValue]) {
NSLog(#"Balance: %li | Cost: %# |-> Sufficient amount!", [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else {
messageAlert = [[UIAlertView alloc] initWithTitle:#"Not enough bubbles!!" message:#"You need to collect more bubbles or purchase them from our store!" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Buy", nil]; [messageAlert show];
} NSLog(#"Cell ID: %li | Balance: %li | Cost: %#", rowID, [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else if (rowID == 2) {
if ([RWGameData sharedGameData].regularBubbleCount >= [megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier] intValue]) {
NSLog(#"Balance: %li | Cost: %# |-> Sufficient amount!", [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else {
messageAlert = [[UIAlertView alloc] initWithTitle:#"Not enough bubbles!!" message:#"You need to collect more bubbles or purchase them from our store!" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Buy", nil]; [messageAlert show];
} NSLog(#"Cell ID: %li | Balance: %li | Cost: %#", rowID, [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else if (rowID == 3) {
if ([RWGameData sharedGameData].regularBubbleCount >= [megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier] intValue]) {
NSLog(#"Balance: %li | Cost: %# |-> Sufficient amount!", [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else {
messageAlert = [[UIAlertView alloc] initWithTitle:#"Not enough bubbles!!" message:#"You need to collect more bubbles or purchase them from our store!" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Buy", nil]; [messageAlert show];
} NSLog(#"Cell ID: %li | Balance: %li | Cost: %#", rowID, [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else if (rowID == 4) {
if ([RWGameData sharedGameData].regularBubbleCount >= [megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier] intValue]) {
NSLog(#"Balance: %li | Cost: %# |-> Sufficient amount!", [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
} else {
messageAlert = [[UIAlertView alloc] initWithTitle:#"Not enough bubbles!!" message:#"You need to collect more bubbles or purchase them from our store!" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Buy", nil]; [messageAlert show];
} NSLog(#"Cell ID: %li | Balance: %li | Cost: %#", rowID, [RWGameData sharedGameData].regularBubbleCount, megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]);
}
}
#end
You don't actively drive individual cells in a UITableView this way. You drive the dataSource that the table uses.
The dataSource should alert the table that data has changed. (Check the fetchedResultsController code in a sample project that Xcode creates for a project using Core Data.)
You can do several things to get the table and cell to update:
Call [myTable reloadData] (crudest, but easy for very few cells)
Call beginUpdate, signal the changes, call endUpdate (the fetchedResultsController way)
For custom cells, they can use KVO or NSNotificationCenter with the data source objects and update themselves when signaled. When cells are recycled, they need to unsubscribe. When reused they subscribe again. (No updates will be needed if they are not on-screen.)
For the first two, the table will start calling 'cellForRowAtIndexpath' for the cells it needs.
You can use -(UITableViewCell *)tableView:cellForRowAtIndexPath: for retrieving a specific cell from the tableView. Just provide the relevant index for the cell you want to reference with indexPathForRow:inSection:.
Problem solved.
I went ahead and did something very primitive, but it works. I'm sure there are many downfalls to this, but I can update it to be more reliable in the future.
In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, I added the following:
if (indexPath.row == 0) {
cell.regularBubbleCostLabel.text = [NSString stringWithFormat:#"%#", megaBubbleUpgradeFees[[RWGameData sharedGameData].megaBubbleUpgradeTier]];
} ...
I have in my .h file:
#import <UIKit/UIKit.h>
#import "SQLClient.h"
#interface mgrViewController : UIViewController <UITableViewDelegate, UITableViewDataSource,
SQLClientDelegate>{
NSMutableArray *pajaros;
}
#property (weak, nonatomic) IBOutlet UITableView *miTabla;
#property (nonatomic, retain)NSMutableArray *pajaros;
#end
And in my .m file:
#import "mgrViewController.h"
#import "Vista2.h"
#import "SQLClient.h"
#interface mgrViewController ()
#end
#implementation mgrViewController
#synthesize miTabla;
#synthesize pajaros;
- (void)viewDidLoad
{
[super viewDidLoad];
SQLClient* client = [SQLClient sharedInstance];
client.delegate = self;
[client connect:#"xxx.xxx.xxx.xxx:xxxx" username:#"xxxxxxxxxxx" password:#"xxxxxxxxxxxx" database:#"xxxxxxxxxxx" completion:^(BOOL success) {
if (success)
{
pajaros =[[NSMutableArray alloc]init];
[client execute:#"SELECT field FROM table WHERE field='xxxxxxxxx'" completion:^(NSArray* results) {
NSMutableString* resulta = [[NSMutableString alloc] init];
for (NSArray* table in results)
for (NSDictionary* row in table)
for (NSString* column in row){
//[results appendFormat:#"\n%# = %#", column, row[column]];
[resulta appendFormat:#"\n%#", row[column]];
[pajaros addObject:resulta];
}
[client disconnect];
}];
}
}];
self.miTabla.delegate = self;
self.miTabla.dataSource = self;
}
#pragma mark - SQLClientDelegate
- (void)error:(NSString*)error code:(int)code severity:(int)severity
{
NSLog(#"Error #%d: %# (Severity %d)", code, error, severity);
[[[UIAlertView alloc] initWithTitle:#"Error" message:error delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil] show];
}
- (void)message:(NSString*)message
{
NSLog(#"Message: %#", message);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return pajaros.count;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"celdaPajaros";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// elementos que contienen cada celda con sus tags
UILabel *labelTitulo = (UILabel *) [cell viewWithTag:10];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
labelTitulo.text = [pajaros objectAtIndex:indexPath.row];
return cell;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 70.f;
}
#end
If I add a count for my NSMutableArray pajaros after the line of code [pajaros addObject:resulta];and I print that count, the result is 1, because my conditional where is for select a data. But if put a count in other part of my code, the result is 0.
My question is how I retain the data in my NSMutableArray for use in:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return pajaros.count;
}
and in:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"celdaPajaros";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// elementos que contienen cada celda con sus tags
UILabel *labelTitulo = (UILabel *) [cell viewWithTag:10];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
labelTitulo.text = [pajaros objectAtIndex:indexPath.row];
return cell;
}
?
Thanks for the help, I'm new in Objective-C.
If I initialize pajaros with a data in:
- (void)viewDidLoad
{
[super viewDidLoad];
pajaros = [NSMutableArray arrayWithObjects:#"Bird1", nil];
self.miTabla.delegate = self;
self.miTabla.dataSource = self;
}
And run my app, the labelTitulo show me Bird1. My second question is: why when I add data to my NSMutableArray pajaros from a Data Base and run my app, it's show me nothing?
Thanks.
When using properties, it's best to include self.. Try self.pajaros = [[NSMutableArray alloc]init]; and likewise in the other places where you just use pajaros.
So I've been trying this for a while now and it is completely frustrating me but here is a brief summary of what I am trying to do. I have a LocationTableViewController with a plus button on the top right to add new locations to the table view. When that happens, I enter the LocationEditViewController where I can enter the name of the location I want to add. After adding my text and hitting the save location button I want the code to bring me back to the LocationTableViewController and there in my table I see my newly added location. Posted below is the code of the two view controllers. Hopefully you guys can help me thanks a ton!!
#import <UIKit/UIKit.h>
#import "Location.h"
#import "User.h"
#interface LocationEditViewController : UIViewController <UITextFieldDelegate>
#property (strong, nonatomic) Location *location;
#property (strong, nonatomic) User *user;
#property (strong, nonatomic) UITextField *locationNameField;
- (void)saveLocation:(id) sender;
#end
#import "LocationEditViewController.h"
#interface LocationEditViewController ()
#end
#implementation LocationEditViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = #"Edit";
self.location = [[Location alloc] init];
self.user = [[User alloc] init];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *locationLabel = [[UILabel alloc] init];
locationLabel.frame = CGRectMake(20,15,50,30);
locationLabel.text = #"Name:";
[self.view addSubview:locationLabel];
self.locationNameField = [[UITextField alloc] init];
self.locationNameField.frame = CGRectMake(15,50,290,30);
self.locationNameField.borderStyle = UITextBorderStyleBezel;
self.locationNameField.keyboardType = UIKeyboardTypeDefault;
self.locationNameField.delegate = self;
[self.view addSubview:self.locationNameField];
UIButton *saveLocationButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
saveLocationButton.frame = CGRectMake(15,400,290,50);
[saveLocationButton setTitle:#"Save Location" forState:UIControlStateNormal];
[saveLocationButton addTarget:self action:#selector(saveLocation:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:saveLocationButton];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)saveLocation:(id)sender {
self.location.name = self.locationNameField.text;
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:self.user.createdLocations];
[tempArray addObject:self.location];
self.user.createdLocations = [[NSArray alloc] initWithArray:tempArray];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location Added"
message:#"This location is now accessable in the locations tab"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
[self.tabBarController.tabBar.items[1] setBadgeValue:[NSString stringWithFormat:#"%i",self.user.createdLocations.count]];
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"somethingAddedNotification" object:nil];
}];
}
/*
#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
Here is the LocationTableViewController code:
#import <UIKit/UIKit.h>
#import "User.h"
#interface LocationTableViewController : UITableViewController
#property (strong, nonatomic) NSArray *locations;
#property (strong, nonatomic) User *user;
#property (strong, nonatomic) id _observer;
- (void) addLocationPressed;
#end
#import "LocationTableViewController.h"
#import "LocationEditViewController.h"
#import "LocationViewController.h"
#interface LocationTableViewController ()
#end
#implementation LocationTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
self.title = #"Locations";
self.user = [[User alloc] init];
UIBarButtonItem *addLocationButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addLocationPressed)];
self.navigationItem.rightBarButtonItem = addLocationButton;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Location *loc = [[Location alloc] init];
//self.user.createdLocations = #[loc];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void) addLocationPressed
{
LocationEditViewController *locationEditVC = [[LocationEditViewController alloc] init];
[self presentViewController:locationEditVC animated:YES completion:nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.user.createdLocations.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.textLabel.text = [self.user.createdLocations[indexPath.row] name];
NSLog(#"%#", [self.user.createdLocations[indexPath.row] name]);
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
LocationViewController *locationVC = [[LocationViewController alloc] init];
locationVC.location = self.user.createdLocations[indexPath.row];
[self.navigationController pushViewController:locationVC animated:YES];
}
- (void)viewWillAppear:(BOOL)animated {
__observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"somethingAddedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *notification)
{
[self.tableView reloadData];
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:__observer];
}
For additional information here is the user class where I am getting the array
#import <Foundation/Foundation.h>
#import "Location.h"
#interface User : NSObject
#property (strong, nonatomic) Location *profilePhoto;
#property (strong, nonatomic) NSString *location;
#property (strong, nonatomic) NSArray *createdLocations;
-(id) initWithTitle: (Location *) aLoc
detail: (NSString *) aDet
filename: (NSArray *) aLocList;
//-(id)initWithJSON;
//+(NSString *)getPathToArchive;
//+(User *)getUser;
//+(void)saveUser:(User *)aUser;
#end
#import "User.h"
#import "Location.h"
#implementation User
- (id)init;
{
self = [self initWithTitle: [[Location alloc] init]
detail: #"Temp"
filename: [[NSArray alloc] init]];
return self;
}
-(id) initWithTitle: (Location *) aLoc
detail: (NSString *) aDet
filename: (NSArray *) aLocList
{
self = [super init];
if (self) {
self.profilePhoto = aLoc;
self.location = aDet;
self.createdLocations = aLocList;
}
return self;
}
#end
and the Locations class if necessary
#import <Foundation/Foundation.h>
#interface Location : NSObject
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *detail;
#property (strong, nonatomic) NSString *filename;
#property (strong, nonatomic) NSString *thumbnail;
-(id) initWithTitle: (NSString *) aTitle
detail: (NSString *) aDetail
filename: (NSString *) aFilename
thumbnail: (NSString *) aThumbnail;
#end
#import "Location.h"
#implementation Location
-(id)init
{
self = [self initWithTitle:#"Title"
detail:#"Detail"
filename:#"placeholder.jpg"
thumbnail:#"placeholder.jpg"];
return self;
}
-(id)initWithTitle:(NSString *)aTitle
detail:(NSString *)aDetail
filename:(NSString *)aFilename
thumbnail:(NSString *)aThumbnail
{
self = [super init];
if (self) {
self.name = aTitle;
self.detail = aDetail;
self.filename = aFilename;
self.thumbnail = aThumbnail;
}
return self;
}
#end
Hopefully you guys can help me! Thanks again!!!
Have you set a breakpoint on...
[self.tableView reloadData];
...in your observer block? Does it get hit? Separately, Drew Crawford is wary of that API you are using (http://sealedabstract.com/code/nsnotificationcenter-with-blocks-considered-harmful/).
Like the comment said, this is definitely a problem, and may in fact be the root cause. You must use the __weak reference inside the block or else NSNotificationCenter owns a strong reference to self and self owns a strong reference to NSNotificationCenter, and you have a retain cycle.
- (void)viewWillAppear:(BOOL)animated {
__weak LocationTableViewController *weakSelf = self;
__observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"somethingAddedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *notification)
{
[weakSelf.tableView reloadData];
}];
}
I'm trying to use the MWFeedParser library in my app. On my homescreen, I have a view controller named NewsViewController.
In the MWFeedParser library, the root view controller is called RootViewController. I've tried to copy all the code from the RootViewController into the NewsViewController .H + .M and in IB I've linked the tableview to "dataSource" and "delegate". But when my app starts the tableview is empty.
Here's how to code looks like:
.H:
#import <UIKit/UIKit.h>
#import "MWFeedItem.h"
#import "MWFeedParser.h"
#interface NewsViewController : UITableViewController <MWFeedParserDelegate, UITableViewDelegate, UITableViewDataSource> {
// Parsing
MWFeedParser *feedParser;
NSMutableArray *parsedItems;
// Displaying
NSArray *itemsToDisplay;
NSDateFormatter *formatter;
IBOutlet UITableView *tableView;
}
// Properties
#property (nonatomic, retain) NSArray *itemsToDisplay;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(IBAction)goHome;
#end
.M:
#import "NSString+HTML.h"
#import "MWFeedParser.h"
#import "DetailTableViewController.h"
#implementation NewsViewController
#synthesize itemsToDisplay, tableView;
#pragma mark -
#pragma mark View lifecycle
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"News", #"News");
self.tabBarItem.image = [UIImage imageNamed:#"icon_news"]; }
return self;
}
- (void)viewDidLoad
{
label.shadowOffset = CGSizeMake(0.0f, 1.0f);
label.textColor = [UIColor colorWithRed:0xB3/249.0 green:0xB3/252.0 blue:0xB3/253.0 alpha:1];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Date
// Setup
formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
parsedItems = [[NSMutableArray alloc] init];
self.itemsToDisplay = [NSArray array];
// Refresh button
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh)];
// Parse
NSURL *feedURL = [NSURL URLWithString:#"http://www.mywebsite.com/feed/"];
feedParser = [[MWFeedParser alloc] initWithFeedURL:feedURL];
feedParser.delegate = self;
feedParser.feedParseType = ParseTypeFull; // Parse feed info and all items
feedParser.connectionType = ConnectionTypeAsynchronously;
[feedParser parse];
UIImage *someImage = [UIImage imageNamed:#"back_active1#2x.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated {
static BOOL first = YES;
if (first) {
UIViewController *popup = [[Home1ViewController alloc] initWithNibName:#"Home1ViewController" bundle:nil];
[self presentViewController:popup animated:NO completion:nil];
first = NO;
}
}
#pragma mark -
#pragma mark Parsing
// Reset and reparse
- (void)refresh {
self.title = #"Refreshing...";
[parsedItems removeAllObjects];
[feedParser stopParsing];
[feedParser parse];
self.tableView.userInteractionEnabled = NO;
self.tableView.alpha = 0.3;
}
- (void)updateTableWithParsedItems {
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO]]];
self.tableView.userInteractionEnabled = YES;
self.tableView.alpha = 1;
[self.tableView reloadData];
}
#pragma mark -
#pragma mark MWFeedParserDelegate
- (void)feedParserDidStart:(MWFeedParser *)parser {
NSLog(#"Started Parsing: %#", parser.url);
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedInfo:(MWFeedInfo *)info {
NSLog(#"Parsed Feed Info: “%#”", info.title);
self.title = info.title;
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item {
NSLog(#"Parsed Feed Item: “%#”", item.title);
if (item) [parsedItems addObject:item];
}
- (void)feedParserDidFinish:(MWFeedParser *)parser {
NSLog(#"Finished Parsing%#", (parser.stopped ? #" (Stopped)" : #""));
[self updateTableWithParsedItems];
}
- (void)feedParser:(MWFeedParser *)parser didFailWithError:(NSError *)error {
NSLog(#"Finished Parsing With Error: %#", error);
if (parsedItems.count == 0) {
self.title = #"Failed"; // Show failed message in title
} else {
// Failed but some items parsed, so show and inform of error
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Parsing Incomplete"
message:#"There was an error during the parsing of this feed. Not all of the feed items could parsed."
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alert show];
}
[self updateTableWithParsedItems];
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return itemsToDisplay.count;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
MWFeedItem *item = [itemsToDisplay objectAtIndex:indexPath.row];
if (item) {
// Process
NSString *itemTitle = item.title ? [item.title stringByConvertingHTMLToPlainText] : #"[No Title]";
NSString *itemSummary = item.summary ? [item.summary stringByConvertingHTMLToPlainText] : #"[No Summary]";
// Set
cell.textLabel.font = [UIFont boldSystemFontOfSize:15];
cell.textLabel.text = itemTitle;
NSMutableString *subtitle = [NSMutableString string];
if (item.date) [subtitle appendFormat:#"%#: ", [formatter stringFromDate:item.date]];
[subtitle appendString:itemSummary];
cell.detailTextLabel.text = subtitle;
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Show detail
DetailTableViewController *detail = [[DetailTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
detail.item = (MWFeedItem *)[itemsToDisplay objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detail animated:YES];
// Deselect
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
Please help me fix this!
you can follow the following link to use MWFeedParser : https://0club1.blogspot.in/
If your Table view is empty, you could have got the following error:
NSURLSession/NSURLConnection HTTP load failed
To allow HTTP, we need to allow arbitrary loads in App Transport Security Settings. Select info.plist in your project, in Information property list add new list as App Transport Security Settings.
Within that add Allow Arbitary Loads and mark it as YES.
I know this question has been asked before but mine is different. My app has an add button and edit button that deletes/adds table views. I want every cell that is created by the user to go to the same view. I've been looking everywhere for the code but I can't find it. BTW the ____ is just a placeholder. The table coding is in the app delegate and I have a second view controller for the view that is loaded when a row is clicked.
AppDelegate.h
#interface _____AppDelegate : NSObject <UIApplicationDelegate> {
CustomCellViewController *customCellViewController;
IBOutlet UIWindow *window;
IBOutlet UITableViewCell *customCell;
NSMutableArray *data;
IBOutlet UITableView *mainTableView;
IBOutlet UINavigationItem *navItem;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
#property (nonatomic, retain) CustomCellViewController *customCellViewController;
- (IBAction)addRowToTableView;
- (IBAction)editTable;
- (NSString *)dataFilePath;
#end
AppDelegate.m
#import "______AppDelegate.h"
#implementation ______AppDelegate;
#synthesize window;
#synthesize navController=_navController;
#synthesize customCellViewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSArray *archivedArray = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataFilePath]];
if (archivedArray == nil) {
data = [[NSMutableArray alloc] init];
} else {
data = [[NSMutableArray alloc] initWithArray:archivedArray];
}
// Override point for customization after application launch
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
return YES;
}
- (IBAction)addRowToTableView {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"New Product" message:#"What is the name of your product?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[alert addTextFieldWithValue:#"" label:#"Name of product..."];
UITextField *tf = [alert textFieldAtIndex:0];
tf.clearButtonMode = UITextFieldViewModeWhileEditing;
tf.keyboardType = UIKeyboardTypeURL;
tf.keyboardAppearance = UIKeyboardAppearanceAlert;
tf.autocapitalizationType = UITextAutocapitalizationTypeNone;
tf.autocorrectionType = UITextAutocorrectionTypeNo;
[alert show];
}
-(void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
UITextField *tf = [alert textFieldAtIndex:0];
[data addObject:tf.text];
[self saveData];
[mainTableView reloadData];
}
}
- (IBAction)editTable {
UIBarButtonItem *leftItem;
[mainTableView setEditing:!mainTableView.editing animated:YES];
if (mainTableView.editing) {
leftItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(editTable)];
} else {
leftItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editTable)];
}
navItem.rightBarButtonItem = leftItem;
[self saveData];
[mainTableView reloadData];
}
- (IBAction)endText {
}
- (NSInteger)numberOfSectionInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifer = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:"Cell"] autorelease];
}
cell.textLabel.text = [data objectAtIndex:indexPath.row];
return cell;
}
- (NSString *)dataFilePath {
NSString *dataFilePath;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
dataFilePath = [[documentDirectory stringByAppendingPathComponent:#"applicationData.plist"] retain];
return dataFilePath;
}
- (void)saveData {
[NSKeyedArchiver archiveRootObject:[data copy] toFile:[self dataFilePath]];
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[data removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath {
NSString *item = [[data objectAtIndex:fromIndexPath.row] retain];
[data removeObject:item];
[data insertObject:item atIndex:toIndexPath.row];
[item release];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)dealloc {
[window release];
[_navController release];
[customCellViewController release];
[super dealloc];
}
#end
I don't mean to be harsh, but you have a lot of basics to learn. ARC will make your life much easier and your code better, by eliminating the need to manually manage memory (for the most part). You can enable it when you first start a project. You should.
Why is an App Delegate managing a table view? No, no no. The app delegate is supposed to respond to system-level events, not run your whole application. You need a separate view controller. Find some tutorials around the web and see how a basic app using a table view is structured. There are many. My favorites are on raywenderlich.com