NSString value not retained - objective-c

I'm trying to assign data from a string to another string within a different viewcontroller however it seems that the data is not retained - i get a null response in NSLog. I would like to know why, thanks ..

Try changing the order a bit, as below, and use retain instead of copy:
SchoolDetailViewController *schoolController = [[SchoolDetailViewController alloc]initWithNibName:nil bundle:nil];
schoolController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
schoolController.courseDetails = #"passing new content";
[self presentModalViewController:schoolController animated:YES];
NSLog(#" %#",schoolController.courseDetails); // 'passing new content' is shown
.h
NSString *courseDetails;
#property (nonatomic, retain) NSString *courseDetails;
.m
#synthesize courseDetails;
- (void)viewDidLoad {
NSLog(#" text : %#",courseDetails); // returns null ... why?
[super viewDidLoad];
}
This should work.

Well that is because the viewDidLoad method is called when you present the view controller with or without animation.
So just flip these 2 statements
[self presentModalViewController:schoolController animated:YES];
schoolController.courseDetails = #"passing new content";
like this
schoolController.courseDetails = #"passing new content";
[self presentModalViewController:schoolController animated:YES];
And then check the results once again...

Related

UIViewController maintains state after being nilled

In my app, I made a BookViewController class that displays and animates the pages of a book and a MainMenuViewController class that displays a set of books the user can read.
In the latter class, when the user taps on one of the books, a function is called that should create a completely new instance of BookViewController, but for some reason the instance maintains its state (i.e. it resumes from the page the user left off).
How can this be if I set it to nil? What am I missing here? (Note that I'm using ARC).
MainMenuViewController.m
#interface MainMenuViewController ()
#property (strong) BookViewController *bookViewController;
#end
#implementation MainMenuViewController
#synthesize bookViewController;
-(void)bookTapped:(UIButton *)sender{
NSString *bookTitle;
if(sender == book1button) bookTitle = #"book1";
else if(sender == book2button) bookTitle = #"book2";
bookViewController = nil;
bookViewController = [[BookViewController alloc] initWithBookTitle:bookTitle];
[self presentViewController:bookViewController animated:YES completion:nil];
}
BookViewController.h
#interface BookViewController : UIViewController
-(id)initWithBookTitle:(NSString *)bookTitle;
#end
BookViewController.m
#implementation BookViewController
-(id)initWithBookTitle:(NSString *)theBookTitle{
self = [super init];
if(self){
bookTitle = [NSString stringWithFormat:#"%#", theBookTitle];
[self setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
NSLog(#"init a BookViewController with bookTitle: %#", bookTitle);
}
return self;
}
edit 1:
Every time a book is tapped, bookTapped: is called, and thee console always prints:
2012-08-31 16:29:51.750 AppName[25713:c07] init a BookViewController with bookTitle: book1
So if a new instance of BookViewController is being created, how come it seems to be returning the old one?
edit 2:
I inserted NSLog(#"bookViewController %#",bookViewController); just before the line [self presentViewController:bookViewController. The console output is:
2012-08-31 16:37:41.426 Henry[25784:c07] bookViewController <BookViewController: 0x6a21540>
2012-08-31 16:38:23.321 Henry[25784:c07] bookViewController <BookViewController: 0xe425540>
2012-08-31 16:38:53.393 Henry[25784:c07] bookViewController <BookViewController: 0x6839330>
Your variables are declared outside of the #implementation of the class (you are declaring global variables).
I suspect that you are using the ivars instead of the properties. Please replace bookViewController with self.bookViewController.
Try:
if(self){
self.bookTitle
The variables that were maintaing their state in the new instance were declared thus:
#import "BookViewController.h"
int currentPage = 0;
#implementation BookViewController
-(id)initWithBookTitle:(NSString *)theBookTitle{
...
So I managed to fix the issue by initialising the variables in the init method:
-(id)initWithBookTitle:(NSString *)theBookTitle{
self = [super init];
if(self){
currentPage = 0; //added this line
bookTitle = [NSString stringWithFormat:#"%#", theBookTitle];
[self setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
NSLog(#"init a BookViewController with bookTitle: %#", bookTitle);
}
return self;
}
But this doesn't solve the underlying problem, which is that doing this:
bookViewController = [[BookViewController alloc] initWithBookTitle:bookTitle];
[self presentViewController:bookViewController animated:YES completion:nil];
still presents a bookViewController with the old value for currentPage! This might be because I'm not declaring it as a property, nor initialising it in the init method... Any thoughts?

NSMutableArray as instance variable alway null

After many hours wasted, I officially turn to the experts for help!
My problem lies with using a NSMutableArray as an instance variable, and trying to both add objects and return the array in a method in my class. I am obviously doing something fundamentally wrong and would be grateful for help...I have already tried all the suggestions from other similar questions on stackoverflow, read apples documentation, and basically all combinations of trial and error coding I can think of. The mutable array just alway returns (null). I've even tried creating properties for them, but still the array returns (null) and then I also am running into memory management problems due to the retain while setting the property, and the init in the init method for the class.
Here is what I am trying to do:
1) Loop through a series of UISwitches and if they are 'switched on', add a string to the NSMutableArray
2) Assign this mutable array to another array in another method
Any help much appreciated,
Andy
And for some code...
fruitsViewController.h
#import <UIKit/UIKit.h>
#interface fruitsViewController : UIViewController
{
NSMutableArray *fruitsArr;
UISwitch *appleSwitch;
UISwitch *orangeSwitch;
}
#property (nonatomic,retain) NSMutableArray *fruitsArr; // ADDED ON EDIT
#property (nonatomic,retain) IBOutlet UISwitch *appleSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *orangeSwitch;
- (IBAction)submitButtonPressed:(id)sender;
#end
fruitsViewController.m
#import "fruitsViewController.h"
#implementation fruitsViewController
#synthesize fruitsArr; // ADDED ON EDIT
#synthesize appleSwitch, orangeSwitch;
/* COMMENTED OUT ON EDIT
-(id)init
{
if (self = [super init]) {
// Allocate memory and initialize the fruits mutable array
fruitsArr = [[NSMutableArray alloc] init];
}
return self;
}
*/
// VIEW DID LOAD ADDED ON EDIT
- (void)viewDidLoad
{
self.fruitsArr = [[NSMutableArray alloc] init];
}
- (void)viewDidUnload
{
self.fruitsArr = nil;
self.appleSwitch = nil;
self.orangeSwitch = nil;
}
- (void)dealloc
{
[fruitsArr release];
[appleSwitch release];
[orangeSwitch release];
[super dealloc];
}
- (IBAction)submitButtonPressed:(id)sender
{
if ([self.appleSwitch isOn]) {
[self.fruitsArr addObject:#"Apple"; // 'self.' ADDED ON EDIT
}
if ([self.orangeSwitch isOn]) {
[self.fruitsArr addObject:#"Orange"; // 'self.' ADDED ON EDIT
}
NSLog(#"%#",self.fruitsArr); // Why is this returning (null) even if the switches are on?!
[fruitsArr addObject:#"Hello World";
NSLog(#"%#",self.fruitsArr); // Even trying to add an object outside the if statement returns (null)
}
#end
It seems like your init function is never called. If you're initializing this view controller from a NIB, you need to use initWithCoder. If not, just declare your fruitsArr in viewDidLoad.
Use view did load instead of init...
- (void)viewDidLoad
{
fruitsArr = [[NSMutableArray alloc] init];
}
Change that init for viewDidLoad and see what happens
Is your init method ever being called (in complicationsViewController). Add a NSLog to check this, you might be calling initWithNib: maybe.
At viewDidUnload you should remove self.fruitsArr = nil;, or, if you want to keep it, then initialize the fruitsArr in viewDidLoad (and remove it from init).
because fruitsArr don't be init.
you should do this first:
fruitsArr = [[NSMutableArray alloc] init];
so, I think you don't run - (id)init before you use fruitsArr.

Using initWithObjects: causes crash, but initWithCapacity: followed by addObject: does not

A really strange problem. I have to init an array in - (void)viewDidLoad.
The array, prjMemberArray is declared as a property:
#property(nonatomic, retain) NSMutableArray* prjMemberArray;
If I use this
prjMemberArray = [[NSMutableArray alloc] initWithObjects:#"someone",#"someone",#"someone" ,nil];
with release called in viewDidUnload,
then when the view loaded , it will crashes immediately But when I use this:
prjMemberArray = [[NSMutableArray alloc] initWithCapacity:0];
[prjMemberArray addObject:#"someone"];
it works well. Can anyone explain this? I use a storyboard to present the current view controller, like this:
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
prj_Detail = [sb instantiateViewControllerWithIdentifier:#"ProjectDetailVC"];
[self presentModalViewController:prj_Detail animated:YES];
Where prjMemberArray is a property of prj_Detail.
Are you sure you have not misspelled items and written e.g. "someone" instead of #"someone" in the crashing scenario?
Don't forget to use self when referring to properties. Here's the a safe way to declare that without having to worry about leaks:
Header:
#property(nonatomic, retain) NSMutableArray* prjMemberArray;
Implementation:
#synthesize prjMemberArray=_prjMemberArray;
- (void) viewDidLoad {
[super viewDidLoad];
NSMutableArray *prjMemberArray = [[NSMutableArray alloc] initWithObjects:#"someone", #"someone", #"someone" ,nil];
self.prjMemberArray = prjMemberArray;
[prjMemberArray release];
}
- (void) dealloc {
[_prjMemberArray release];
[super dealloc];
}
#property creates the getter and setter for your variable but is often confused for a variable itself. When they released XCode4 I believe they added the ability to set what you want the instance variable to be named by doing:
#synthesize prjMemberArray=_prjMemberArray;
Before XCode4 you simply did:
#synthesize prjMemberArray;
So what #property is doing behind the scenes is a little something like this:
-(NSMutableArray*) prjMemberArray {
return _prjMemberArray;
}
-(void) setPrjMemberArray:(NSMutableArray *) val {
if( _prjMemberArray != nil )
[prjMemberArray release];
_prjMemberArray = [val retain];
}
So don't think of #property as a variable itself and remember to always use self when referring to them. That should save you a lot of pain and a few memory leaks as well.

Passing objects to a different view

I have an object name usr. I want to change views and I want to pass it along to the new view. How can I pass this object?
RVUser *usr = [[RVUser alloc] init];
UIViewController* exampleController = [[exampleClass alloc] initWithNibName:#"RVListsController" bundle:nil];
if (exampleController) {
exampleController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:exampleController animated:YES];
if (exampleController.title == nil) {
NSLog(#"enters");
//exampleController.title = #"Revistas Destacadas";
}
[exampleController release];
}
}
One way of doing it is to declare a property of type RVUser on exampleClass and assign it to that property after creating exampleController.
You should set properties BEFORE using [self presentModalViewController:exampleController animated:YES];
RVUser *usr = [[RVUser alloc] init];
UIViewController* exampleController = [[exampleClass alloc] initWithNibName:#"RVListsController" bundle:nil];
if (exampleController) {
exampleController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
if (exampleController.title == nil) {
NSLog(#"enters");
//exampleController.title = #"Revistas Destacadas";
}
//TODO: Set exampleController properties, declared as #property (nonatomic, release) RVUser *passedUsr;
//exampleController.passedUsr = usr;
//[usr release];
[self presentModalViewController:exampleController animated:YES];
}
[exampleController release];
You'll want to declare the instance of ExampleController as your custom UIViewController instead of UIViewController - this will give you code completion and compile time warnings if you call a method/property on it that doesn't exit. Then, change your definition of exampleClass (read the naming convention guide also) to have a property of type RVUser, like so:
#property (nonatomic, retain) RVUser *user;
And in the implementation file:
#synthesize user;
Now you can pass your object to that controller before you display it:
ExampleController.user = usr;
You really should read the intro guides on the Apple developer site, they cover this and a lot more that you need to know if you want to write iOS apps.

Objective-C NSMutableArray Count Causes EXC_BAD_ACCESS

I've been stuck on this for days and each time I come back to it I keep making my code more and more confusing to myself, lol. Here's what I'm trying to do. I have table list of charges, I tap on one and brings up a model view with charge details. Now when the model is presented a object is created to fetch a XML list of users and parses it and returns a NSMutableArray via a custom delegate. I then have a button that presents a picker popover, when the popover view is called the user array is used in an initWithArray call to the popover view. I know the data in the array is right, but when [pickerUsers count] is called I get an EXC_BAD_ACCESS. I assume it's a memory/ownership issue but nothing seems to help. Any help would be appreciated.
Relevant code snippets:
Charge Popover (Charge details model view):
#interface ChargePopoverViewController .....
NSMutableArray *pickerUserList;
#property (nonatomic, retain) NSMutableArray *pickerUserList;
#implementation ChargePopoverViewController
#synthesize whoOwesPickerButton, pickerUserList;
- (void)viewDidLoad {
JEHWebAPIPickerUsers *fetcher = [[JEHWebAPIPickerUsers alloc] init];
fetcher.delegate = self;
[fetcher fetchUsers];
}
-(void) JEHWebAPIFetchedUsers:(NSMutableArray *)theData {
[pickerUserList release];
pickerUserList = theData;
}
- (void) pickWhoPaid: (id) sender {
UserPickerViewController* content = [[UserPickerViewController alloc] initWithArray:pickerUserList];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:content];
[popover presentPopoverFromRect:whoPaidPickerButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
content.delegate = self;
}
User Picker View Controller
#interface UserPickerViewController .....
NSMutableArray *pickerUsers;
#property(nonatomic, retain) NSMutableArray *pickerUsers;
#implementation UserPickerViewController
#synthesize pickerUsers;
-(UserPickerViewController*) initWithArray:(NSMutableArray *)theUsers {
self = [super init];
if ( self ) {
self.pickerUsers = theUsers;
}
return self;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
// Dies Here EXC_BAD_ACCESS, but NSLog(#"The content of array is%#",pickerUsers); shows correct array data
return [pickerUsers count];
}
I can provide additional code if it might help. Thanks in advance.
You declare the ivar holding the array as this...
#property (nonatomic, retain) NSMutableArray *pickerUserList;
But then you have a method implemented like this:
-(void) JEHWebAPIFetchedUsers:(NSMutableArray *)theData {
[pickerUserList release];
pickerUserList = theData;
}
You aren't retaining theData and you aren't calling the synthesized setter. If you did Build and Analyze, it should catch this problem and tell you about it. If not, file a bug.