ViewController load methods called when view disappears? - objective-c

I've got the following code in a viewController. I've got a NavigationController on the view (which is the child view - the code for the parent is working fine)
What happens is when I select an option on the parent, this viewController loads. The user can select an option from the child viewController to open a PDF file with a DocumentInteractionController (which works fine).
The problem is when I try going back to the parent viewController, messages are being sent to the child viewController as if it's still allocated. I saw something similar when I set it up since there were multiple calls to the methods in the child viewController.
Any thoughts on what I'm doing wrong?
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
#synthesize node;
#synthesize replies;
#synthesize docController;
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointZero animated:NO];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.docController init];
// Do any additional setup after loading the view from its nib.
}
- (void) dealloc
{
[self.docController release];
[super dealloc];
}
- (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
{
if (self.replies == nil)
{
self.replies = [[NSArray alloc] init];
self.actions = [[NSArray alloc] init];
}
if(self.replies.count == 0)
{
self.replies = [self.node nodesForXPath:#"./question/reply/text" error:nil];
self.actions = [self.node nodesForXPath:#"./question/reply/response/action" error:nil];
}
return self.replies.count;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"QuestionCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Get the object to display and set the value in the cell
NSString *cellText = [[replies objectAtIndex:indexPath.row] stringValue];
cell.textLabel.text = cellText;
return cell;
}
- (void) showOptionsMenu:(NSString *) fileName
{
NSString *fileToOpen = [[NSBundle mainBundle] pathForResource:fileName ofType:#"pdf"];
NSURL *fileURL = [NSURL fileURLWithPath:fileToOpen];
self.docController = [self setupControllerWithURL:fileURL usingDelegate:self];
bool didShow = [self.docController presentOptionsMenuFromRect:CGRectMake(0, 0, 150, 150) inView: self.view animated:YES];
if(!didShow)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"" message:#"Sorry, app not found" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *action = [[self.actions objectAtIndex:indexPath.row] stringValue];
[self showOptionsMenu:action];
}
- (UIDocumentInteractionController *) setupControllerWithURL: (NSURL *) fileURL usingDelegate:(id <UIDocumentInteractionControllerDelegate>) interactionDelegate
{
UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
#end
EDIT
Adding the code for the parent view controller...maybe there's something I'm doing wrong in there? I'm using GDataXML to load a Q&A app based on the contents of an XML file...
#implementation ViewController
#synthesize currentReply;
#synthesize questions;
- (void)viewDidLoad
{
[super viewDidLoad];
[self setUpQuestions];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc
{
[super dealloc];
}
- (void) setUpQuestions
{
// create and init NSXMLParser object
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"query" ofType:#"xml"];
NSData *xml_data = [[NSData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *xmlDoc = [[GDataXMLDocument alloc] initWithData:xml_data options:0 error:&error];
NSArray *rootDataArray = [xmlDoc.rootElement nodesForXPath:#"//query" error:nil];
for (GDataXMLElement *rootDataElement in rootDataArray)
{
// Allocate the query object
self->query = [[[Query alloc] init] autorelease];
// Name
NSArray *query_title = [rootDataElement elementsForName:#"text"];
if (query_title.count > 0)
{
GDataXMLElement *queryTitle = (GDataXMLElement *) [query_title objectAtIndex:0];
self->query.queryTitle = [[[NSString alloc] initWithString:queryTitle.stringValue] autorelease];
}
NSArray *query_first_question = [rootDataElement elementsForName:#"question"];
NSArray *replies = [NSArray alloc];
questions = [[NSMutableArray alloc] init];
if(query_first_question.count == 1)
{
GDataXMLElement *fq = (GDataXMLElement *) [query_first_question objectAtIndex:0];
replies = [fq elementsForName:#"reply"];
for (GDataXMLElement *replyElement in replies)
{
[questions addObject:replyElement];
}
}
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Only one section.
return 1;
}
- (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection:(NSInteger)section
{
switch(section)
{
case 0:
return questions.count;
break;
case 1:
return 1;
break;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"QuestionCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
// Get the object to display and set the value in the cell.
GDataXMLElement *questionAtIndex = questions[indexPath.row];
NSString *cellText = [[[questionAtIndex elementsForName:#"text"] objectAtIndex:0] stringValue];
cell.textLabel.text = cellText;
//cell.textLabel.text = [[questionAtIndex elementsForName:#"text"] objectAtIndex:0];
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSMutableString *msg = [NSMutableString new];
//[msg appendString:#"You selected row: "];
//[msg appendString:[NSString stringWithFormat:#"%i",indexPath.row]];
//UIAlertView *alertMsg = [[UIAlertView alloc] initWithTitle:#"Row Selected" message:msg delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
//[alertMsg show];
if (questions != nil)
{
GDataXMLElement *selectedReply = (GDataXMLElement *) [questions objectAtIndex:indexPath.row];
DetailViewController *dvc = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
dvc.node = selectedReply;
[self.navigationController pushViewController:dvc animated:YES];
[dvc release];
}
}
EDIT
I've tried profiling and looking for zombies, but when the crash occurs there are no zombie objects flagged. It throws the following error in the console:
[UIView _forgetDependentConstraint:]: message sent to deallocated instance 0x1e8ab810

I have seen this Issue before also !!!
Answer : Turn Off "AutoLayout".
I am guessing the error occurred due to new feature in ios called AutoLayout. It looks like Compiler has created some NSLayoutConstraint objects and due to some reason the objects were released more than they should. Deletion and Re-Creation, forces Xcode to Re-Build the Constraints. But,I am not 100% sure.
Try to Un-Check "AutoLayout", if it can solve your Problem.

Your DetailViewController code is fine - not actually fine, as you're leaking self.replies and self.actions, and the [self.docController init] is very odd and probably wrong (always alloc and init together) - but the lifecycle code on this end looks fine. The problem is almost certainly in the parent view controller (or possibly the document controller if you're creating a retain cycle there). If the parent view controller is holding onto a pointer to the detail view controller, it won't actually be deallocated and accessing the view or any property thereof will cause -viewDidLoad to be called again.

From what I understood, your parent view controller is setting the node here:
dvc.node = selectedReply;
and it's never being released from your DetailViewController.
I'm assuming that your GDataXMLElement in the DetailViewController header is set as "retain".
And there's some leaking problems as icodestuff pointed out.

Related

UITableView - Populate labels on each cell

I have the following code, which should populate a UITableView with information provided from a JSON variable. Problem is that none of the labels (TitleLabel and ReferenceLabel) populate and I'm left with the default label titles. What am I missing (this is driving me crazy)?
TableView.h
#import <UIKit/UIKit.h>
#define kGETUrl #"http://localhost/RtnDBScript.php"
#interface TableViewController : UITableViewController {
NSMutableArray *json;
}
TableView.m
#import "TableViewController.h"
#import "TableViewCell.h"
#interface TableViewController ()
#end
#implementation TableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void) getData:(NSData *) data {
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self.tableView reloadData];
}
- (void) start {
NSURL *url = [NSURL URLWithString:kGETUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
[self getData:data];
}
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self start];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [json count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TableViewCell";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *info = [json objectAtIndex:indexPath.row];
cell.TitleLabel.text = [info objectForKey:#"Name"];
cell.DescriptionLabel.text = [info objectForKey:#"Message"];
return cell;
}
In the above code i get the following error 'Property 'TitleLabel' not found on object of type 'CountryTableViewCell'
cell.TitleLabel.text = [info objectForKey:#"Name"];
cell.DescriptionLabel.text = [info objectForKey:#"Message"];
TableViewCell.h
#import <UIKit/UIKit.h>
#interface CountryTableViewCell : UITableViewCell{
}
TabelViewCell.m
#implementation CountryTableViewCell
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
Any and all help appreciated.
Can you please try?
CountryTableViewCell *cell = (CountryTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// It seems that you are using prototype cell so no need to alloc.
//if (cell == nil) {
// cell = [[CountryTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
//}
Just make sure CellIdentifier is matching to the identifier in storyboard prototype cell.
Update:
If you can see the default text then the problem can be in binding the labels (Labels are created but not bound to outlet).
To verify put a log right after assignment of text.
NSLog([cell.TitleLabel description]);
Can you please try
cell.TitleLabel.text = [NSString stringWithFormat:#"%#",[info objectForKey:#"Name"]];// Tell the system explicitly that this value will be NSString.

Problems Populating TableView with NSMutableArray

I'm using SudzC for an iPhone app. I'm succesfully calling my ASP.Net webservice and pulling the needed data into an NSMutable array called tableData. I have a tableView that should display the contents of tableData; however this is not working. I've looked for hours at this problem. I'm very new to the Objective C world so I'm thinking it's a small oversight on my part. I've linked my TableView to the ViewController (delegate/datasource) as well.
Here's is the code I have:
#import "ViewController.h"
#import "DocumentServiceJSONService.h"
#interface ViewController ()
#end
#implementation ViewController
NSMutableArray *tableData;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)viewWillAppear:(BOOL) animated {
tableData = [[NSMutableArray alloc] init];
DocumentServiceJSONService* service = [[DocumentServiceJSONService alloc] init];
[service GetAllEMSDocumentsXMLAsString: self action:#selector(handleGetAllEMSDocuments:)];
[super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) handleGetAllEMSDocuments:(id) result {
if ([result isKindOfClass:[NSError class]]) {
//if an error has occurred, handle it
return;
}
if([result isKindOfClass: [SoapFault class]]) {
return;
}
NSString* xmlString = result;
CXMLDocument *xmlDoc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];
NSArray *nodes = NULL;
nodes = [xmlDoc nodesForXPath:#"//EMSDocuments" error:nil];
for (CXMLElement *node in nodes) {
NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
int counter;
for (counter = 0; counter < [node childCount]; counter++) {
[item setObject:[[node childAtIndex:counter] stringValue] forKey:[[node childAtIndex:counter] name]];
}
//[item setObject:[[node attributeForName:#"DisplayName"] stringValue] forKey:#"DisplayName"];
NSString *displayName = [item objectForKey:#"DisplayName"];
[tableData addObject:displayName];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
#end
Any advice is appreciated.
Make sure you have in your .h the delegate and datasource correctly set:
#interface YourViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
And if you are using XIBs for the user interface, that the tableview is connected to the File's Owner as datasource and delegate.
--
EDIT:
Creating a Outlet for you tableview:

My second level detail controller is not showing the initWithObjects in my array in the viewDidLoad method

I am creating a Two Level table view. And the second view is supposed to have the list of the movies I have listed below in my viewDidLoad method, but it is not showing.(You can see my screen shots attached)Does anyone know which file where I can look to see why it is not showing? The code below is from my DisclosureButtonController.m file which is to display this information after I hit the Disclosure Buttons instance on the First Level screen.
Regards,
#import "LWWDisclosureButtonController.h"
#import "LWWAppDelegate.h"
#import "LWWDisclosureDetailController.h"
#interface LWWDisclosureButtonController ()
#property (strong, nonatomic) LWWDisclosureDetailController *childController;
#end
#implementation LWWDisclosureButtonController
#synthesize list;
#synthesize childController;
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//{
// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
//if (self) {
// Custom initialization
//}
//return self;
//}
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *array = [[NSArray alloc] initWithObjects:#"Toy Story", #"A Bug's Life", #"Toy Story 2", #"Monsters, Inc.", #"Finding Nemo", #"The Incredibles", #"Cars", #"Ratatouille", #"WALL-E", #"Up", #"Toy Story 3", #"Cars 2", #"Brave", nil];
self.list = array;
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.list = nil;
self.childController = nil;
// Release any retained subviews of the main view.
}
#pragma mark -
#pragma mark Table Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [list count];//
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString * DisclosureButtonCellIdentifier = #"DisclosureButtonCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DisclosureButtonCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:DisclosureButtonCellIdentifier];
}
NSUInteger row = [indexPath row];
NSString *rowString = [list objectAtIndex:row];
cell.textLabel.text = rowString;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
#pragma mark -
#pragma mark Table Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Hey, boss do you see the disclosure button?" message:#"If you're trying to drill down, touch that instead mate!" delegate:nil cancelButtonTitle:#"Won't happen again" otherButtonTitles:nil];
[alert show];
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath: (NSIndexPath *)indexPath
{
if (childController == nil)
{
childController = [[LWWDisclosureDetailController alloc]initWithNibName:#"LWWDisclosureDetail" bundle:nil];
}
childController.title = #"Disclosure Button Pressed";
NSUInteger row = [indexPath row];
NSString *selectedMovie = [list objectAtIndex:row];
NSString *detailMessage = [[NSString alloc]initWithFormat:#"You pressed the disclosure button for %#.", selectedMovie];
childController.message = detailMessage;
childController.title = selectedMovie;
[self.navigationController pushViewController:childController animated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Why not start the array with the VC instead of after the VC loads? Try overriding the init method.
- (id) init {
if((self == [super init])) {
//load your array here and set
}
return self;
}
That way, on older devices, you don't have to wait after the view loads to see the array. But, however, this is my preference. I love to override init methods and create my own.
Also, for some weird reason on my SDK, I have to use NSMutableArray instead of NSArray or it won't work. Maybe you have the same issue?
Also, I've noticed NSString *selectedMovie. Instead of using just "row", use the getter indexPath.row.
Hope these suggestions helped!
Call:
[self.tableView reloadData]; (put in place of self.tableView the var or property connected to the tableView)
after the:
self.list = array;
code line in the viewDidLoad method
and put a
NSLog(#"number of rows: %d", [self.list count]);
in
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [list count];//
}
to check if it is not zero.

Reloading a table view after NSURLConnection succeeds

I'm new to Xcode, so bear with me:
I have a table view that I'm trying to reload once the NSURLConnection succeeds. I have a number of messages that help me guide me along the way... but when I call the reload upon the table view, the table doesn't repopulate.
JsonViewController.h:
#import <UIKit/UIKit.h>
#interface JsonViewController : UITableViewController {
NSMutableArray *theTweets;
IBOutlet UITableView *tview;
NSMutableData *responseData;
}
#property (nonatomic, retain) NSMutableArray *theTweets;
#property (nonatomic, retain) UITableView *tview;
#end
JsonViewController.m:
#import "JsonViewController.h"
#import "SBJson.h"
#implementation JsonViewController
#synthesize theTweets;
#synthesize tview;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
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.
}
- (void) dealloc {
[theTweets release];
[super dealloc];
}
- (NSMutableArray*)theTweets {
return [[theTweets retain] autorelease];
}
- (void) setTheTweets:(NSMutableArray *)newTweets {
if (newTweets != theTweets) {
[newTweets retain];
[theTweets release];
theTweets = newTweets;
NSLog(#"Setting new tweets...");
[tview reloadData];
}
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
tview.delegate = self;
responseData = [[NSMutableData data] retain];
theTweets = [NSMutableArray array];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://search.twitter.com/search.json?q=AriaPoker&result_type=recent"]];
[[NSURLConnection alloc] initWithRequest: request delegate:self];
NSLog(#"Trying to get feed upon initialization");
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
// methods that are not important
#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.
NSLog(#"Number of the tweets count at this point: %d", [theTweets count]);
return [theTweets 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] autorelease];
}
NSLog(#"Number of the tweets count at this point: %d", [theTweets count]);
// Configure the cell...
NSDictionary *aTweet = [theTweets objectAtIndex:[indexPath row]];
//cell.textLabel.text = [aTweet objectForKey:#"text"];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.font = [UIFont systemFontOfSize:12];
cell.textLabel.numberOfLines = 4;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.text = #"Test";
cell.detailTextLabel.text = #"haha";
//NSURL *url = [NSURL URLWithString:[aTweet objectForKey:#"profile_image_url"]];
//NSData *data = [NSData dataWithContentsOfURL:url];
//cell.imageView.image = [UIImage imageWithData:data];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
NSLog(#"Loading cells in table");
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
}
#pragma mark NSURLConnection Delegate Methods
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
//do nothing
NSLog(#"A connection error has occurred!");
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *results = [[responseString JSONValue] retain];
NSLog(#"Number of Rows: %d", [results count]);
NSMutableArray *allTweets = [results objectForKey:#"results"];
//[viewController setTweets:allTweets];
theTweets = allTweets;
NSLog(#"Number of misc2: %d", [theTweets count]);
[results release];
[tview reloadData];
}
#end
I'm wondering what I'm doing wrong here.
In connectionDidFinishLoading change from this:
theTweets = allTweets;
to this:
self.theTweets = allTweets;
or this way if you prefer:
[self setTheTweets:allTweets];
You weren't invoking the setter method, so it wasn't getting retained.
As suggested by progrmr try to call the setter method, or simply change definition of theTweets property to #dynamic theTweets in this case when you try to set property, the custom setter method will be called.

Invalid argument type to unary expression

I have this program with a tableView as my first view. I have also implemented (or at least tried to) a search bar on top of the view. Have used several hours to search for a solution, but without positive results.
#import "FirstViewController.h"
#import "NSDictionary-MutableDeepCopy.h"
#implementation FirstViewController
#synthesize listData, table, search, allNames, names, keys;
#pragma mark -
#pragma mark Custom Methods
- (void)resetSearch {
NSMutableDictionary *allNamesCopy = [self.allNames mutableDeepCopy];
self.names = allNamesCopy;
[allNamesCopy release];
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
[keyArray addObjectsFromArray:[[self.allNames allKeys]
sortedArrayUsingSelector:#selector(compare:)]];
self.keys = keyArray;
[keyArray release];
}
-(void)handleSearchForTerm:(NSString *)searchTerm {
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
[self resetSearch];
for (NSString *key in self.keys) {
NSMutableArray *array = [names valueForKey:key];
NSMutableArray *toRemove = [[NSMutableArray alloc] init];
for (NSString *name in listData) {
if ([name rangeOfString:searchTerm
options:NSCaseInsensitiveSearch].location == NSNotFound)
[toRemove addObject:name];
}
if ([array count] == [toRemove count])
[sectionsToRemove addObject:key];
[array removeObjectsInArray:toRemove];
[toRemove release];
}
[self.keys removeObjectsInArray:sectionsToRemove];
[sectionsToRemove release];
[table reloadData];
}
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"sortednames" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
self.names = dict;
self.allNames = dict;
[dict release];
[self resetSearch];
[table reloadData];
[table setContentOffset:CGPointMake(0.0, 44.0)animated:NO];
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
NSArray *array = [[NSArray alloc] initWithObjects:
// A larger amount of objects here.
self.listData = array;
[array release];
[super viewDidLoad];
}
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
/*
// 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];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.listData = nil;
self.table = nil;
self.search = nil;
self.allNames = nil;
self.names = nil;
self.keys = nil;
}
- (void)dealloc {
[listData release];
[search release];
[table release];
[allNames release];
[keys release];
[names release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return ([keys count] > 0) ? [keys count] : 1;
}
- (NSInteger)tableView:(UITableView *)aTableView
numberOfRowsInSection: (NSInteger)section {
return [self.listData count];
if ([keys count] == 0)
return 0;
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *) extracted_method: (UITableViewCell *) cell {
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
static NSString *sectionsTableIdentifier = #"sectionsTableIdentifier";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:
sectionsTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: sectionsTableIdentifier] autorelease];
}
cell.backgroundColor = [UIColor clearColor];
cell.textColor = [UIColor whiteColor];
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.text = [nameSection objectAtIndex:row];
[self extracted_method: cell].text = [listData objectAtIndex:row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section {
if ([keys count] == 0)
return nil;
NSString *key = [keys objectAtIndex:section];
return key;
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return keys;
}
#pragma mark -
#pragma mark Table View Delegate Methods
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[search resignFirstResponder];
return indexPath;
}
#pragma mark -
#pragma mark Search Bar Delegate Methods
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSString *searchTerm = [searchBar text];
[self handleSearchForTerm:searchTerm];
}
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchTerm {
if ([searchTerm length] == 0) {
[self resetSearch];
[table reloadData];
return;
}
[self handleSearchForTerm:searchTerm];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
search.text = #"";
[self resetSearch];
[table reloadData];
[searchBar resignFirstResponder];
}
#end
Ok guys. My problem is that this doesnt get the search function to work. In addition I receive siginal SIGABRT at this line:
NSString *key = [keys objectAtIndex:section];
So I need help with two things:
1: I need to get that SIGABRT away.
Error log message: * Terminating app due to uncaught exception
'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]:
index 0 beyond bounds for empty array'
That is I don't store any data in keys. how would I do that? and what would I store?
2: Want the search function to search in my listData array!
Thanks in advance - hope u can help!
You have not finished your sectionIndexTitlesForTableView: method. Right now it is:
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return keys;
There is no closing }, so the compiler thinks everything after that is still part of that method. When you try to define the next method, use use - (NSIndexPath *) to indicate that it is an instance method which returns NSIndexPath*, but the compiler thinks you are trying to subtract something.
The solution is simple: Add the } to the end of sectionIndexTitlesForTableView:.
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return keys;
}