Problems with InitWithData - iphone

I am trying to InitWithData a viewcontroller with multiple data like this:
NewsDetailViewController *anotherViewController = [[NewsDetailViewController alloc] initWithData:[oldEntries objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:anotherViewController animated:YES];
[anotherViewController release];
[newsTableView deselectRowAtIndexPath:indexPath animated:NO];
So this is the current: InitWithData:initWithData:[oldEntries objectAtIndex:indexPath.row]];
Now I need the InitWithData to push 2 of these objects:
[oldEntries objectAtIndex:indexPath.row];
[reviewEntries objectAtIndex:indexPath.row];
How can I do this?
I receive the current data like this in the NewsDetailController:
- (id)initWithData:(NSDictionary *)data {
if (self == [super init]) {
rssData = [data copy];
}
return self;
}
And rssData is a NSDictionary..

change your init method to
- (id)initWithOldData:(NSDictionary *)oldData
andReviewData:(NSDictionary *)revData {
if (self == [super init]) {
rssOldData = [oldData copy];
rssReviewData = [revData copy];
}
return self;
}
and call it using
[[NewsDetailViewController alloc]
initWithOldData:[oldEntries objectAtIndex:indexPath.row]
andReviewData:[reviewEntries objectAtIndex:indexPath.row]];
Of course you need to declare rssOldDataand rssReviewData in your NewsDetailViewController too.

Related

Memory-management in iOS Programming

I have a little problem with memory management in my iOS App. I load an XML and set all Values in this XML to Spezific Objects. Now my problem is when i reload the XML every 15 - 20 reloads of this XML my app Crash on Parsing here is a sample of my parser.
EDIT: Here ist the ERROR when NSZombie is Enabled if NSZombie is disabled I didn't get an ERROR message.
-[CFNumber retain]: message sent to deallocated instance
thanks for help.
EDIT:
the beginning of my Code:
- (id)init
{
self = [super init];
if (self) {
TheObjects *theObjects = [[TheObjects alloc] init];
[self parse];
}
return self;
}
- (void) reload{
reload = YES;
TheObjects *theTmpObjects = [[TheObjects alloc] init];
[self parse];
}
- (void)parse{
for (id xmlOBject in xmlObjects){
MyObject *object = [[MyObject alloc] init];
object.number1 = [NSNumber numberWithInt:1];
object.number2 = [NSNumber numberWithInt:2];
object.number3 = [NSNumber numberWithInt:3];
if (reload)
[theTmpObjects.objects addObject:object];
else
[theObjects.objects addObject:object];
[object release];
}
//later in my code
TheObjects *localTheTmpObjects = nil;
if (reload){
localTheTmpObjects = theObjects;
theObjects = theTmpObjects;
}
if ([delegate respondsToSelector:#selector(finished:)]){
[delegate performSelector:#selector(finished:) withObject:theObjects];
}
if(reload)
[localTheTmpObjects release];
}
remove the line [localTheTmpObjects release]
you don't own the object
at the end, call the `[localTheTmpObjects autorelease];`
this is because if you release array, all its objects are released and hence may cause crash, when your array may in use
- (id)init
{
self = [super init];
if (self) {
TheObjects *obbjects = [[TheObjects alloc] init];
theObjects = objects;
[objects releas];
[self parse];
}
return self;
}
- (void) reload{
reload = YES;
TheObjects *obbjects = [[TheObjects alloc] init];
thetmpObjects = objects;
[objects releas]; [self parse];
}
- (void)parse{
for (id xmlOBject in xmlObjects){
MyObject *object = [[MyObject alloc] init];
object.number1 = [NSNumber numberWithInt:1];
object.number2 = [NSNumber numberWithInt:2];
object.number3 = [NSNumber numberWithInt:3];
if (reload)
[theTmpObjects.objects addObject:object];
else
[theObjects.objects addObject:object];
[object release];
}
//later in my code
TheObjects *localTheTmpObjects = nil;
if (reload){
localTheTmpObjects = theObjects;
theObjects = theTmpObjects;
}
if ([delegate respondsToSelector:#selector(finished:)]){
[delegate performSelector:#selector(finished:) withObject:theObjects];
}
}

NSArray clears after 3 times view did load

I have an NSArray that contains a couple of items. The NSArray is loaded into a uitableview from another class. when I back out of the detail view and re-enter (for the 3rd time), the NSArray is empty and the tableview is empty as well. What is happening? (I am using arc so I don't think it is a leak)
- (void)viewDidLoad {
myMatch = [[Match alloc] initWithId:1 OpponentId:13];
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *askCellIdent = #"askCell";
static NSString *answerCellIdent = #"answerCell";
if (indexPath.row == 0)
{
AskCell *cell = [tv dequeueReusableCellWithIdentifier:askCellIdent];
if (cell==nil) {
cell = [[AskCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:askCellIdent];
}
cell.nameLabel.text = #"Albert asked:";
cell.questionLabel.text = [NSString stringWithFormat:#"%#", [[myMatch.chat objectAtIndex:indexPath.row] objectAtIndex:1]];
return cell;
}
if (indexPath.row == 1)
{
AnswerCell *cell = [tv dequeueReusableCellWithIdentifier:answerCellIdent];
if (cell==nil) {
cell = [[AnswerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:answerCellIdent];
}
cell.nameLabel.text = #"Hugh answered:";
cell.answerLabel.text = [NSString stringWithFormat:#"%#", [[myMatch.chat objectAtIndex:indexPath.row] objectAtIndex:1]];
return cell;
}
}
Here is the init code of the my match class:
- (id) initWithId:(NSInteger)yourId OpponentId:(NSInteger)opId {
self = [super init];
if (self != nil) {
//set your id and opponents id to the match.
[self setUserId:yourId];
[self setUserId:opId];
JSON = #"[{\"opponentId\":\"4\",\"chat\":[[\"1\",\"Does he have a beard?\"],[\"1\",\"No.\"]]}]";
//initiate the chat array.
chat = [[NSMutableArray alloc] init ];
[self loadMatch];
}
return self;
}
and here is the chat property/synthesize
NSMutableArray *chat;
#property (nonatomic, retain) NSMutableArray *chat;
#synthesize chat;
No idea whats going on, because the slog of the array is empty too!
Declare an int varable repeatCount in appDelegate
- (void)viewDidLoad
{
[super viewDidLoad];
ypurAppDelegate *appDelegate = (yourAppDelegate *)[[UIApplication sharedApplication] elegate];
appDelegate.repeatCount++;
if(appDelegate.repeatCount %3==0)
{
[array removeAllObjects];
[tableview reloaddata];
}
}
Use self.chat = [[[NSMutableArray alloc] init ]autorelease]; to initialize your array
Instead ViewDidLoad, allocate the object in initWithCoder.
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if( self )
{
myMatch = [[Match alloc] initWithId:1 OpponentId:13];
}
return self;
}
I think it's a problem with the populating the NSMutableArray as only once will viewDidLoad will be called. You should insert values into array in viewWillAppear Method or initiate the match class in initWithCoder.

init an array in initWithNibName

I am trying to set up an array in my UIViewController. The nib gets loaded into my app, sometimes repeatedly. I am adding this to my initWithNibName to init the array
NSMutableArray *temp = [[NSMutableArray alloc] initWithObjects:#"one",#"two",#"three",#"four",#"five",nil];
[self setScoreArray:temp];
[temp release];
scoreArray is a MutableArray with synthesized properties. When I go to access the array in viewDidLoad I get [[self scoreArray] count] as 0. Also, when I load the nib repeatedly I get a bad access error. Any suggestions? Am I missing a step. Thanks. I am synthesizing the property for the array, in my class declaration:
NSMutableArray *_scoreArray;
then
#property (nonatomic, retain) NSMutableArray *scoreArray;
then in my implementation
#synthesize scoreArray =_scoreArray;
and in my dealloc
[_scoreArray release], _scoreArray = nil;
I'm editing this post to show how I'm loading the nibs with my RootViewController
- (void) createNewSlide:(NSInteger)slideIndex {
NSDictionary *slideObj = (NSDictionary *)[[self slidesDataSource] objectAtIndex:slideIndex - 1];
NSString *currentTitle = [slideObj objectForKey:#"title"];
[[self slideTitle] setText:currentTitle];
NSString *currentContent = [slideObj objectForKey:#"contentString"];
NSString *currentContentType = [slideObj objectForKey:#"contentType"];
if ([self currentVC] != nil) {
[[self currentVC] reset];
[self setCurrentVC:nil];
}
if ([currentContentType isEqualToString:#"slide"])
{
[[self containerViewController] loadImage:currentContent];
}
else if ([currentContentType isEqualToString:#"quiz"])
{
NSInteger quizNum = [[slideObj objectForKey:#"quizNum"] integerValue];
NSLog(#"%s%#%d",__FUNCTION__,#"quizNum ",quizNum);
QuizViewController *quizView = [[QuizViewController alloc] initWithNibName:#"QuizViewController" bundle:nil];
[self setCurrentVC:quizView];
[quizView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"PIDView"])
{
PIDViewController *PIDView = [[PIDViewController alloc] initWithNibName:#"PIDView" bundle:nil];
[self setCurrentVC:PIDView];
[PIDView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"LoginView"])
{
LoginViewController *login = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self setCurrentVC:login];
[login release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"VakView"])
{
VakViewController *vakView = [[VakViewController alloc] initWithNibName:#"VakView" bundle:nil];
[self setCurrentVC:vakView];
[vakView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"PlanView"])
{
PlanViewController *planView = [[PlanViewController alloc] initWithNibName:#"PlanView" bundle:nil];
[self setCurrentVC:planView];
[planView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
Thanks for your insights.
PlanView is the one that causes the problem. But it is not when it loads, it's when something else loads after it. I have run the analyzer and it reports no memory leaks.
BTW, currentVC is a synthesized property.
How is your UIViewController being created? If it is being created via another nib, then -initWithNibName:bundle: doesn't get called. Instead, -initWithCoder: and -awakeFromNib are called.

Objective-C: Properties error when setting a value to a NSArray property

I'm getting some kind of error when setting a value to a NSArray property of my code. I will send you de code and the debugger output.
#interface RootViewController : UITableViewController {
#private
NSArray* regioesArray;
}
#property(nonatomic, retain) NSArray *regioesArray;
#implementation RootViewController
#synthesize regioesArray;
- (void)viewDidLoad {
[super viewDidLoad];
//Set Title
self.title = #"RegiƵes";
self.regioesArray = nil;
}
- (void)viewDidUnload {
self.regioesArray = nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0 && self.regioesArray != nil){
return [regioesArray count];
} else {
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
// Set up the cell
Zona *zona = (Zona *)[regioesArray objectAtIndex:indexPath.row];
cell.text = [zona nome];
[cell.contentView addSubview: [self getDetailDiscolosureIndicatorForIndexPath: indexPath]];
[zona release];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic
}
- (void)viewWillDisappear:(BOOL)animated {
}
- (void)viewDidDisappear:(BOOL)animated {
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[super dealloc];
[regioesArray release];
}
- (UIButton *) getDetailDiscolosureIndicatorForIndexPath: (NSIndexPath *) indexPath
{
UIButton *button = [UIButton buttonWithType: UIButtonTypeDetailDisclosure];
button.frame = CGRectMake(320.0 - 44.0, 0.0, 44.0, 44.0);
[button addTarget:self action:#selector(detailDiscolosureIndicatorSelected:) forControlEvents:UIControlEventTouchUpInside];
return button;
}
- (void) detailDiscolosureIndicatorSelected: (UIButton *) sender
{
//
// Obtain a reference to the selected cell
//
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: [self.tableView indexPathForSelectedRow]];
//
// Do something like render a detailed view
//
/// ...
}
#end
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
NSArray * regioes = [self createRegions];
rootViewController.regioesArray = regioes;
[regioes release];
[rootViewController release];
[aNavigationController release];
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
The error is on the line rootViewController.regioesArray = regioes;
I can't ser any value o this property, not even "nil".
Here is the debug:
2010-10-16 01:35:43.965 TransitoRio[4224:207] *** -[RootViewController setRegioesArray:]: unrecognized selector sent to instance 0x1813ef0
2010-10-16 01:35:43.968 TransitoRio[4224:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[RootViewController setRegioesArray:]: unrecognized selector sent to instance 0x1813ef0'
What may be happening?
As asked, here is the "createRegions" method:
- (NSArray *)createRegions {
NSMutableArray *regioes = [[NSMutableArray alloc] init];
Zona *regiao = [[Zona alloc] init];
regiao.nome = #"Zona Sul";
[regioes addObject:regiao];
[regiao release];
regiao = [[Zona alloc] init];
regiao.nome = #"Zona Norte";
[regioes addObject:regiao];
[regiao release];
regiao = [[Zona alloc] init];
regiao.nome = #"Zona Oeste";
[regioes addObject:regiao];
[regiao release];
regiao = [[Zona alloc] init];
regiao.nome = #"Centro";
[regioes addObject:regiao];
[regiao release];
// Sort the regions.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"nome" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
NSArray *sortedRegions = [regioes sortedArrayUsingDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
[regioes release];
[sortedRegions retain];
return sortedRegions;
}
I see that you declared your array to be private in the header file, therefore you shouldn't access the property from outside of the class.

iphone Dev - activity indicator with NSThread not working on Nav controller table view

I really can't get this to work, basically when my JSON feeds loads I want the indicator to show, then hide when it's stopped.
It loads top level menu items 1st "Publishing, Broadcasting, Marketing Services", then when Broadcasting is selected it loads a feed using the JSON framework hosted on Google. Round this load I call startIndicator and stopIndicator using the NSThread. Have I missed something?
#implementation GeneralNewsTableViewController
#synthesize dataList;
#synthesize generalNewsDetailViewController;
#synthesize atLevel;
-(void) startIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView startAnimating];
[pool release];
}
-(void) stopIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView stopAnimating];
[pool release];
}
- (void)viewDidLoad {
NSMutableArray *checker = self.dataList;
if(checker == nil)
{
self.title = NSLocalizedString(#"General1",#"General News");
NSMutableArray *array = [[NSArray alloc] initWithObjects:#"Publishing", #"Broadcasting",#"Marketing Services",nil];
self.dataList = [array retain];
self.atLevel = #"level1";
[array release];
}
UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
//set the initial property
[activityIndicator stopAnimating];
[activityIndicator hidesWhenStopped];
//Create an instance of Bar button item with custome view which is of activity indicator
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
//Set the bar button the navigation bar
[self navigationItem].rightBarButtonItem = barButton;
//Memory clean up
[activityIndicator release];
[barButton release];
[super viewDidLoad];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *level = self.atLevel;
if([level isEqualToString:#"level2"])
{
return 70.0f;
}
else
{
return 40.0f;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstLevelCell = #"FirstLevelCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelCell];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:FirstLevelCell] autorelease];
}
NSInteger row = [indexPath row];
NSString *level = self.atLevel;
if([level isEqualToString:#"level2"])
{
NSMutableArray *stream = [self.dataList objectAtIndex:row];
NSString *newsTitle = [stream valueForKey:#"title"];
if( ![newsTitle isKindOfClass:[NSString class]] )
{
cell.textLabel.text = #"";
}
else
{
cell.textLabel.text = [stream valueForKey:#"title"];
}
cell.textLabel.numberOfLines = 2;
cell.textLabel.font =[UIFont systemFontOfSize:10];
cell.detailTextLabel.numberOfLines = 1;
cell.detailTextLabel.font= [UIFont systemFontOfSize:8];
cell.detailTextLabel.text = [stream valueForKey:#"created"];
NSData *imageURL = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://www.website.co.uk/images/stories/img.jpg"]];
UIImage *newsImage = [[UIImage alloc] initWithData:imageURL];
cell.imageView.image = newsImage;
[imageURL release];
[newsImage release];
}
else
{
cell.textLabel.text = [dataList objectAtIndex:row];
}
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSMutableString *levelType = (NSMutableString *) [dataList objectAtIndex:row];
if(![levelType isKindOfClass:[NSString class]])
{
if(self.generalNewsDetailViewController == nil)
{
GeneralNewsDetailViewController *generalDetail = [[GeneralNewsDetailViewController alloc] initWithNibName:#"GeneralNewsDetailView" bundle:nil];
self.generalNewsDetailViewController = generalDetail;
[generalDetail release];
}
NSDictionary *stream = [self.dataList objectAtIndex:row];
NSString *newsTitle = [stream valueForKey:#"title"];
if( ![newsTitle isKindOfClass:[NSString class]] )
{
generalNewsDetailViewController.newsTitle = #"";
}
else
{
generalNewsDetailViewController.newsTitle =[stream valueForKey:#"title"];
}
generalNewsDetailViewController.newsId = [stream valueForKey:#"id"];
generalNewsDetailViewController.fullText = [stream valueForKey:#"fulltext"];
generalNewsDetailViewController.newsImage = [stream valueForKey:#"images"];
generalNewsDetailViewController.created = [stream valueForKey:#"created"];
HowDo_v1AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.generalNewsNavController pushViewController:self.generalNewsDetailViewController animated:YES];
}
else
{
GeneralNewsTableViewController
*generalSubDetail = [[GeneralNewsTableViewController alloc] initWithNibName:#"GeneralNewsTableView" bundle:nil];
NSMutableArray *array;
NSString *titleSelected = (NSString *) [dataList objectAtIndex:row];
if([titleSelected isEqualToString:#"Publishing"])
{
generalSubDetail.title = #"Publishing news detail";
array = [[NSArray alloc] initWithObjects:#"pub News1", #"pub News2",#"pub News3",nil];
generalSubDetail.atLevel = #"level1";
}
else if ([titleSelected isEqualToString:#"Broadcasting"])
{
generalSubDetail.title = #"Broadcasting news detail";
/// START
[self performSelectorOnMainThread:#selector(startIndicator) withObject:nil waitUntilDone:YES];
if(jSONDataAccessWrapper == nil)
{
jSONDataAccessWrapper = [JSON_DataAccess_Wrapper alloc];
}
array = [jSONDataAccessWrapper downloadJSONFeed];
[self performSelectorOnMainThread:#selector(stopIndicator) withObject:nil waitUntilDone:YES];
generalSubDetail.atLevel = #"level2";
}
else if ([titleSelected isEqualToString:#"Marketing Services"])
{
generalSubDetail.title = #"Marketing Services news detail";
array = [[NSArray alloc] initWithObjects:#"Marketing News1", #"Marketing News2",#"Marketing News3",nil];
generalSubDetail.atLevel = #"level1";
}
generalSubDetail.dataList = array;
[self.navigationController pushViewController:generalSubDetail animated:YES];
[titleSelected release];
}
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
//- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSIndexPath *) section
{
return [self.dataList count];
}
Cheers for any feedback
Frames
It is usually recommended by Apple that operations on user interface should be done on the main thread.
What you can do is to defer the callback into the main thread:
- (void)startIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(startAnimating:) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)startAnimating:(id)sender
{
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView startAnimating];
}
Check out the Thread Guide from Apple. It contains useful information.