SOLVED: Not really a solution, but I just used a .xib rather than trying to use the storyboard thing. Whatever I was trying to do with the storyboard was somehow messing up the TableView delegate methods from being called. Thanks for all the insight you guys provided.
I have a UIViewController that contains a UITableView that should be populated by an array.
Unfortunately the UITableView does not get populated by the array (which is not empty).
My .h file:
#interface Directory : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate> {
NSArray *listData;
NSArray *savedListData;
MKMapView* mapUI;
UISearchBar* searchBar;
NSArray * originalListData;
UITableView* placeList;
DirInfoListing *infoInst;
NSString *searchInit;
NSString *openInit;
NSMutableArray *buildings;}
#property (nonatomic, retain) NSArray *listData;
#property (nonatomic, retain) NSArray *savedListData;
#property (nonatomic, retain) IBOutlet UISearchBar* searchBar;
#property (nonatomic, retain) IBOutlet UITableView* placeList;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list: (NSArray*)array mapView:(MKMapView*) map;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list:(NSArray*)array mapView:(MKMapView*) map search:(NSString*) ss;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list: (NSArray*)array mapView:(MKMapView*) map open:(NSString*) openTx;
-(void)doDBLoad;
#end
And relevant stuff from my .m file:
#import "Directory.h"
#interface Directory ()
#end
#implementation Directory
#synthesize listData, savedListData;
#synthesize searchBar;
#synthesize placeList;
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"ListData count: %lu", (unsigned long)savedListData.count);
//This returns a valid number of 74 items
return [self.savedListData count];
}
/*
* Populates the table with list data and provides title. AND DOES NOT GET CALLED
*/
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *tID = #"tablIDDirect";
UITableViewCell *c = [tableView dequeueReusableCellWithIdentifier:tID];
if(c == nil) {
c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tID];
}
NSInteger r = [indexPath row];
if([self.listData objectAtIndex:r] != nil){
c.textLabel.text = ((DBBuilding*)[self.savedListData objectAtIndex:r]).Name;
c.detailTextLabel.text = ((DBBuilding*)[self.savedListData objectAtIndex:r]).Acronym;
}
c.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return c;
}
/*
* Displays an entry according to the table selection and redirects the user to the Directory Information Listing.
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger r = [indexPath row];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if(infoInst != nil) {
infoInst = nil;
}
infoInst = [[DirInfoListing alloc] initWithNibName:#"DirInfoListing" bundle:nil building:[self.savedListData objectAtIndex:r] map:mapUI];
}
/*
* Notification that the Directory is the active view
*/
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(openInit != nil)
{
[self openEntry:openInit];
openInit = nil;
}
placeList = [[UITableView alloc] init];
placeList.dataSource = self;
placeList.delegate = self;
[placeList reloadData];
}
/*
* Notification that the Directory is no longer the active view
*/
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (void)viewDidLoad
{
NSLog(#"ListData count: %lu", (unsigned long)listData.count);
//Also returns a valid number of 74 objects within the array
savedListData = [[NSArray alloc] initWithArray:listData];
//That get put into another array just for my sanity
[super viewDidLoad];
// Do any additional setup after loading the view.
searchBar.text = searchInit;
[self performSearch:searchInit];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionmethod gets called, but none of the other UITableView delegate methods are called and I am at a loss as to why this happens.
Also, this whole chunk of code is pulled from another one of my apps (That works correctly) using .xibs and DOES NOT use storyboards. This app (the one I'm having problems with) uses storyboards, which I am not very familiar with. I may be doing something wrong with calling and using the storyboard, but I am just not sure. If there may be something related to that I can provide more information.
Could you guys please go over my code and maybe see where I've gone wrong?
Thanks!
In your "viewDidLoad" method, change one line to this:
self.savedListData = [[NSArray alloc] initWithArray:listData];
Except "listData" needs to be something. "self.listData" might be that something, but on my first pass, I do not see where "self.listData" gets populated or set.
With properties, you usually use "self." to access (set and get) everything for the properties everywhere except in the init methods.
The reason the table is not displaying anything is because your "numberOfRowsInSection" method is likely returning zero. Set a breakpoint and check that.
Related
I am working with TableView and wanted Custom TableViewCell to have a Small Image, Name and one custom image (With Tickmark and without Tick) can be on accessory to show if Cell is selected and if it's not selected it will show without Tick image on unselected cells.
And if i want to select multiple cells then it should show Tick image on selected Cells and Untick image on unselected cells and after that when i click on a button then i should be able to get the selected cell id's.
On the tableView i am getting all the values from the server and images also from URL's but the Tickmark and Unselected Tick mark image will be used the project itself.
So far i have created :
Class .h,.m,.xib of "ResultTableCell" of type UITableViewCell and my Main view "Result" with the TableView and a Button on top (on click of button i'll get the values of selected cells)
ResultTableCell.h
#import <UIKit/UIKit.h>
#interface ResultTableCell : UITableViewCell
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#property (nonatomic, retain) IBOutlet UIImageView *thumbImageView;
ResultTableCell.m
#import "ResultTableCell.h"
#implementation ResultTableCell
#synthesize nameLabel,thumbImageView;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
ResultTableCell.xib
The right hand side image on the xib is the place where the accessor image will come.
ResultTableCell.xib
And the main xib
Result.h
#import <UIKit/UIKit.h>
#import "ASIFormDataRequest.h"
#interface Results : UIViewController <UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *nameData;
}
#property (nonatomic, retain)NSMutableArray *nameData;
#property (nonatomic, retain)NSMutableArray *ImageData;
#property (nonatomic, retain)NSMutableArray *idData;
#property (nonatomic, retain)UITableView *table;
#property (nonatomic, retain) IBOutlet UIButton *done;
#property (nonatomic, retain) NSMutableArray *arFors;
-(IBAction)save_done:(id)sender;
Result.m
#import "Results.h"
#import "ResultTableCell.h"
#interface Results ()
#end
#implementation Results
#synthesize arFors;
#synthesize done,nameData,table,addressData,ImageData,idData;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.arFors=[NSMutableArray array];
// I am Getting Name,id and image url data from my HomeViewController
NSLog(#"Name Data from home view is %#",nameData); // 10 Names get's printed in log
NSLog(#"id Data is %#",idData);
NSLog(#"URL image data is %#",ImageData);
table = [[UITableView alloc]initWithFrame:CGRectMake(0, 221, 320, 327) style:UITableViewStylePlain];
table.delegate = self;
table.dataSource = self;
[self.view addSubview:table];
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Name data count is %d",nameData.count);
return nameData.count;
//return 10;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
/* UITableViewCell *cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}*/
static NSString *simpleTableIdentifier = #"ResultTableCell";
ResultTableCell *cell = (ResultTableCell *)[table dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ResultTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if ([self.arFors containsObject:[NSNumber numberWithInt:indexPath.row]]) {
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"table_tick" ]];
}
else {
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"table_add" ]];
}
NSLog(#"data is ************* %#",nameData);
cell.nameLabel.text = [nameData objectAtIndex:indexPath.row];
NSURL * imageURL = [NSURL URLWithString:[ImageData objectAtIndex:indexPath.row]];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image2 = [UIImage imageWithData:imageData];
cell.ImageView.image = image2;
cell.ImageView.contentMode = UIViewContentModeScaleAspectFit;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath %d",indexPath.row);
if ([self.arFors containsObject:[NSNumber numberWithInt:indexPath.row]]) {
[self.arFors removeObject:[NSNumber numberWithInt:indexPath.row]];
}
else{
[self.arFors addObject:[NSNumber numberWithInt:indexPath.row]];
// [self.table cellForRowAtIndexPath:indexPath];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView reloadData];
}
-(IBAction)save_done:(id)sender
{
NSLog(#"selected cell values are %#",self.arFors);
}
Now with this code everything is working fine (tick image is shown on selected cells and untick image on unslected cells and on clicking the Done button i am getting the selected cell values),
But the Problem comes when i tapp on a cell then it like hangs and takes 5-6 seconds of time to change accessor image as it fires [tableView reloadData] in didselectrowatindexpath method so all data reloads again in the tableview and then the accessor image changes, please can any one correct my code or enhance it so that it works fast.
I have tried a lot of ways but i was not able to do it without the reloading of table and if i reload table it takes long time.
Coding help will be much tankful.
Your problem is:
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
Because it downloads all of the image data from the network each time you reload the table view. You should be doing this asynchronously and caching the returned image so you don't need to download it repeatedly. Take a look at a library like SDWebImage to help you with this.
IT IS SOLVED BY #T-X. I've marked the changes with "// SOLUTION" in the code!!!
I have the following issue, if I presentModalViewController, the NSMutableArray "projectsArray" gets reset.
Here is my code:
Here the .h file:
// ViewController.h
#import <UIKit/UIKit.h>
#class AddProject;
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
IBOutlet UITableView *projectsTableView;
UIAlertView *reallyDelete;
BOOL candelButtonClicked;
NSIndexPath *actualIndexPath;
NSMutableArray *projectsArray;
NSInteger ID;
NSString *NAME;
AddProject *addProject;
**ViewController *viewContr; // SOLUTION**
}
- (IBAction)addNewProject:(id)sender;
- (void)addToTableView:(NSString *)projectName;
#property (nonatomic, retain) UIAlertView *reallyDelete;
#property (nonatomic) NSInteger cancelButtonIndex;
#property IBOutlet UITableView *projectsTableView;
#property (nonatomic, retain) AddProject *addProject;
**#property (nonatomic, retain) ViewController *viewContr; // SOLUTION**
#end
Here the .m file:
// ViewController.m
#import "ViewController.h"
#import "CustomTableCell.h"
#import "AddProject.h"
#interface ViewController ()
#end
#implementation ViewController
**#synthesize viewContr; // SOLUTION**
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
projectsArray = [[NSMutableArray alloc] init];
ViewController *element = [[ViewController alloc] init];
element->ID = 1;
element->NAME = #"Demo project";
NSLog(#"viewdidload");
[projectsArray addObject:element];
NSLog(#"1. Array length: %d", [projectsArray count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([projectsArray count] < 1) {
NSLog(#"2. Array length: 0");
return 0;
} else {
NSLog(#"2. Array length: %d", [projectsArray count]);
return [projectsArray count];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *customTableCellIdentifier = #"CustomTableCell";
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:customTableCellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
ViewController *element = [[ViewController alloc] init];
element = [projectsArray objectAtIndex:indexPath.row];
cell.nameLabel.text = element->NAME;
cell.prepTimeLabel.text = [NSString stringWithFormat:#"%i", element->ID];
NSLog(#"3. Array length: %d", [projectsArray count]);
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
reallyDelete = [[UIAlertView alloc] initWithTitle:#"Deleting" message:#"Do your really want to delete that row?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[reallyDelete show];
actualIndexPath = indexPath;
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != [reallyDelete cancelButtonIndex])
{
//If "Yes" clicked delete
[projectsArray removeObjectAtIndex:actualIndexPath.row];
NSLog(#"delete row");
[self.projectsTableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObjects:actualIndexPath, nil] withRowAnimation:YES];
[self.projectsTableView reloadData];
}
}
#pragma mark Edit
- (IBAction)addNewProject:(id)sender {
NSLog(#"4. Array length: %d", [projectsArray count]);
AddProject *addProjectView = [[AddProject alloc] initWithNibName:#"AddProject" bundle:nil];
NSLog(#"4.1 Array length: %d", [projectsArray count]);
addProjectView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
NSLog(#"4.2 Array length: %d", [projectsArray count]);
addProjectView.modalPresentationStyle = UIModalPresentationFormSheet;
NSLog(#"4.3 Array length: %d", [projectsArray count]);
**addProjectView.viewContr = self; // SOLUTION**
[self presentModalViewController:addProjectView animated:YES];
NSLog(#"4.4 Array length: %d", [projectsArray count]);
addProjectView.view.superview.frame = CGRectMake(addProjectView.view.center.x/2.5, addProjectView.view.center.y/3, 800, 600);
NSLog(#"4.5 Array length: %d", [projectsArray count]);
}
- (void)addToTableView:(NSString *)projectName
{
NSLog(#"Project Array: %#", projectsArray);
NSLog(#"addToTableView: %#", projectName);
NSLog(#"5. Array length: %d", [projectsArray count]);
ViewController *element = [[ViewController alloc] init];
element->ID = 2;
element->NAME = projectName;
[projectsArray addObject:element];
NSLog(#"6. Array length: %d", [projectsArray count]);
[self.projectsTableView reloadData];
[self.projectsTableView setNeedsDisplay];
}
- (void)viewDidUnload
{
[self setProjectsTableView:nil];
self.projectsTableView = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
Here the .h file of the modal presented view:
// AddProject.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface AddProject : UIViewController
{
IBOutlet UITextField *projectName;
ViewController *viewContr;
}
- (IBAction)back:(id)sender;
- (IBAction)next:(id)sender;
#property (nonatomic, retain) ViewController *viewContr;
#end
The .m file of the modal presented file:
// AddProject.m
#import "AddProject.h"
#import "ViewController.h"
#interface AddProject ()
#end
#implementation AddProject
**#synthesize viewContr; // SOLUTION I've mist to synthesize it**
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
**// SOLUTION no new allocation/init of ViewController**
}
- (IBAction)back:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)next:(id)sender
{
[viewContr addToTableView:projectName.text];
[viewContr.projectsTableView reloadData];
[viewContr.projectsTableView setNeedsDisplay];
[self dismissModalViewControllerAnimated:YES];
}
- (void)viewDidUnload
{
projectName = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
I've tested the code by using breakpoints and I could locate the issue when the AddProject class "viewDidLoad" starts loading. But I don't know why it resets the array.
You navigate from ViewController Screen to Add project Screen. In Add Project Screen, you add a new project and want to delegate back this information to the ViewController Screen where you came from.
Now, you are trying to have an instance of ViewController in your AddProject, which you newly instantiate in viewDidLoad method and when project is added, you provide the information to it by calling - (void)addToTableView:(NSString *)projectName on it.
This doesn't work because - The instance of ViewController you allocated is a new instance and not the one you navigated from. When you do alloc + init you get a new object. Thus, although you get addToTableView: called on your ViewController, it doesn't work because the ViewController instance that is receiving this message is a new instance and not the one you navigated from.
Thus, all you needed to do is - have a ViewController property in your Add Project, which you would set before navigating. And then you can send message to this property - As explained in this transcript.
I would like to say - However this thing works, it provides tight coupling between the two controllers.
Ideally, This cane be done by making ViewController (where you go navigate from) as a delegate of Add Project (where you navigate to). And then Add Project can delegate the added project to it's delegate by something like - (void) addProjectController:(AddProjectViewController *) controller didAddProject:(NSString *) projectName. This provides lose coupling between the two view controllers. To understand delegation concept, refer to Delegates and Datasources. Alternatively, search for other Stack overflow posts.
You should allocate projectsArray in the init method of the view controller, not in in viewDidLoad. projectsArray = [[NSMutableArray alloc] init]; allocated a new empty array tach time the view is loaded.
Okay my issue is fixed through the stackoverflow chat. The tips for the final solution came from user #T-X. I've added the tips in the code in my question. They are marked with "// SOLUTION".
In Add Project View controller's viewDidLoad method, remove the line
viewContr = [[ViewController alloc] init];. Now make the variable
viewContr in your ViewController class a property. Also synthesize
it. And finally in the - (IBAction)addNewProject:(id)sender method,
before presenting the controller, do - addProjectView.viewContr = self;. It will solve your issue.
(quote from chat.stackoverflow | #T-X)
I am trying to take an array that I loaded from another viewer and put it into a UITableView, not a TableViewController. I don't know how I would do this. Right now I have this code:
CRHCommentSection.m
#import "CRHCommentSection.h"
#import "CRHViewControllerScript.h"
#interface CRHCommentSection ()
#end
#implementation CRHCommentSection
#synthesize observationTable;
NSArray *myArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
myArray = [CRHViewControllerScript theArray];
NSLog(#"%#", myArray);
//NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]];
//[observationTable insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
NSLog(#" in method 1");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#" in method 2");
// Return the number of rows in the section.
return [myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#" in method 3");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [myArray objectAtIndex:indexPath.row];
return cell;
}
CRHCommentSection.h
#import <UIKit/UIKit.h>
#interface CRHCommentSection : UIViewController
#property (weak, nonatomic) IBOutlet UITableView *observationTable;
#end
Since you have posted this same example code more than once, Ill give you the way to do this without using statics. And Yes you do need to set the collection (array) on the view controller not the UITableView as the tableView uses the controller as a datasource.
Lets say you had a UITableView that displayed search results... And you launch this view controller from either some other view or from the application delegate like so..
In your viewController (yours is CRHCommentSection) define a property for the array you are going to populate the table with.
#property (nonatomic,retain, setter=setSearchResults:) NSArray *searchResults; //use your array name here
//BTW please dont call it ARRAY..its confusing.
Also in your commentsController (which would be a better name that what you have) add the setter for
the array
-(void) setSearchResults:(NSArray *)searchResults
{
//in case we loaded this view with results previously release the previous results
if ( _searchResults )
{
[_searchResults release];
}
_searchResults = [searchResults retain];
[_tableView reloadData];
}
When you instantiate the new view controller with the UITableView in it - set the "array",
in your case comments in my case searchResults
_searchResultsViewController = [[SearchResultsViewController alloc] initWithNibName:#"SearchResultsViewController" bundle:nil];
//now set the array on the controller
_searchResultsViewController.searchResults = mySearchResults; //(your array)
Thats a simple way to communicate the array for the table view when you instantiate a view controller.
Also the naming conventions will help you clear things up
If you have a view controller for comments it should be
CommentsViewController
And the array if it contains comments should be called comments - for readability.
Cheers.
As for the rest of the boilerplate setting the datasource and delegate and cellForRow etc,
you got that advice on the last go around so I wont repeat it here.
#bigkm had a good point
#interface SearchResultsViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
Your view controller has to be defined properly as above with the protocols.
You need to set the data source
[self setDataSource:self];
And also add the protocol to your interface.
<UITableViewDataSource>
I am using a UITableView that points to a UITabBarController to display a series of UIWebViews within these tabs.
I would like define a string to be used to construct a URL for each tab based on the item selected. The issue I am facing is how to pass the URL to the StateTrendViewController controller.
StateTableViewController.h
#import <UIKit/UIKit.h>
#interface StateTableViewController : UITableViewController
{
NSArray *StateList;
}
#property (nonatomic, retain) NSArray *StateList;
- (void) buildStateList;
#end
StateTableViewController.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [StateList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSInteger rowNumber = indexPath.row;
NSString *stateName = [StateList objectAtIndex:rowNumber];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = stateName.capitalizedString;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger rowNumber = indexPath.row;
NSString *stateName = [StateList objectAtIndex:rowNumber];
[[self.navigationController.viewControllers objectAtIndex:2] setTitle:stateName.capitalizedString];
}
StateTrendViewController.h
#import <UIKit/UIKit.h>
#interface StateTrendViewController : UIViewController
{
IBOutlet UIWebView *StateTrendView;
IBOutlet NSString *ViewURL;
}
#property (nonatomic, retain) UIWebView *StateTrendView;
#property (nonatomic, retain) NSString *ViewURL;
#end
StateTrendViewController.m
#import "StateTrendViewController.h"
#implementation StateTrendViewController
#synthesize StateTrendView;
#synthesize ViewURL;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void) viewWillAppear:(BOOL)animated
{
NSString *baseURL = #"https://www.google.com/search?q=";
NSString *state = #"test";
NSString *fullURL = [baseURL stringByAppendingString:state];
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; [StateTrendView loadRequest:requestObj];
}
I need to replace the static setting with the sting passed to the controller using the ViewURL property I have setup:
NSString *state = #"test";
I am using a Storyboard in my project in Xcode 4.2.1. How should I go about passing that string value to my controller?
You override prepareForSegue, more detail is here
If all you are passing is a string, the simplest way might be to define a property on your the view controller you are presenting to hold the string. I notice you already have one, *ViewURL defined, but I'm not sure if that's what you've setup for this specific task or if that is already intended for something else.
Based on the code you've shared, I'm assuming that in your didSelectRowAtIndexPath in your table controller, the controller you are setting the title, and presumably later pushing, is an instance of a StateViewController:
[[self.navigationController.viewControllers objectAtIndex:2] setTitle:stateName.capitalizedString];
If this line does indeed reference an instance of StateTrendViewController, you would assign your string in the same way you're assigning title. This needs to be set before you segue into the new view controller (I don't see that code):
[[self.navigationController.viewControllers objectAtIndex:2] setViewURL:#"MyPassedString"] //assign custom property
When your view controller appears on screen, it will have it's property ViewURL already set.
Also note that your naming style for instance variables is not a standard cocoa convention, ivars beginLowerCase. Additionally, it is unusual and may not work to push a TabBar controller inside an existing nav controller, presumably from table view view controller inside an existing nav controller. Typically a TabBar is considered a top-level navigational construct, and you may wish to rethink your architecture accordingly.
Another newbie question, just when I thought I was beginning to get a very
small handle on ios programming. Ugh! I'm following a tutoria from the
appcodeblog.com where I'm building a simple tab bar application utilizing
core data to enter, display, and search vacation destinations. I've worked
through the tutorial and have a working app, but I notice when I select the
"Show Destinations" tab I get the following error. The app seems to continue
working, but the error is logged to the console. I'm trying to debug the
issue and understand exactly what is happening, but I just don't quite
understand what is wrong. I "think" I have an issue with my
ShowDestinations.xib file where I've incorrectly hooked up my objects within
the xib. Any help is MUCH appreciated. Thanks in advance for your help and
time.
Here's the error, "CoreDataTabBarTutorial[1262:207] Failed to call designated
initializer on NSManagedObject class 'Destination'.
I'm not sure what code to provide so I've started out by showing my header
and implementation files ShowDistinationsViewController.h and
ShowDestinationsViewController.m
ShowDistinationsViewController.h
#import <UIKit/UIKit.h>
#interface SearchDestinationsViewController : UIViewController {
UISearchBar *destinationSearchBar;
UITableView *searchTableView;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSArray *fetchedObjects;
}
#property (nonatomic, retain) IBOutlet UISearchBar *destinationSearchBar;
#property (nonatomic, retain) IBOutlet UITableView *searchTableView;
#property (nonatomic, retain) IBOutlet NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) IBOutlet NSManagedObjectContext *managedObjectContext;
#end
ShowDestinationsViewController.m
#import "ShowDestinationsViewController.h"
#import "Destination.h"
#implementation ShowDestinationsViewController
#synthesize destinationsTableView;
#synthesize destinationsArray;
#synthesize fetchedResultsController;
#synthesize managedObjectContext;
// Not sure where the following code came from so I commented it out!!! It didn't seem to break anything when I commented it out
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//{
// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// if (self) {
// // Custom initialization
// }
// return self;
//}
- (void)dealloc
{
[destinationsArray release];
[destinationsTableView release];
[super dealloc];
}
- (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
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma Data Fetch from Core Data
- (void) viewWillAppear:(BOOL)animated
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Destination" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil)
{
// Handle the error.
NSLog(#"mutableFetchResults == nil");
}
[self setDestinationsArray:mutableFetchResults];
[request release];
[destinationsTableView reloadData];
}
#pragma mark -
#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 [destinationsArray 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:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
Destination *destination = [[Destination alloc] init];
destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
cell.textLabel.text = destination.name;
[destination release];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
The problem seems to lie in
Destination *destination = [[Destination alloc] init];
destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
[destination release];
The first line is unnecessary: In Objective-C, Destination* is a pointer to the object, not the real object. The Destination object you want is presumably already in the array. So you don't have to create an object to point to, in the line [[Destination alloc] init], which is gone immediately at the next line. What's going on was
[[Destination alloc] init] creates an object a, destination points to a. a is retained by you.
(Destination *)[destinationsArray objectAtIndex:indexPath.row] gives you another object b, which is not retained by you. destination now points to b. No one holds a any longer.
release is sent to the object pointed to by destination, i.e., to b. This is against the retain-release rule; you should release a, not b!
So, instead, just do
Destination *destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
without the release part.
As an advice: always run Analyze (which is available below the Build menu) when you build your project. The analyzer is designed to catch common types of errors, including yours. Correct your code so that all the analyzer warnings go away; you should always regard the analyzer warning as an error on your part.