Passing objects to a different view - objective-c

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.

Related

iOS Property not found on object of type 'AppDelegate *'

I have two viewControllers accessing a NSNumber on the AppDelegate. One of them can see it, and the other can't. I am totally confused by this.
The one with the problem has this code.
AppDelegate *dataStore = (AppDelegate *)[[UIApplication sharedApplication] delegate];
dataStore.downHUD = [NSNumber numberWithFloat:(float)progress];
The other has this.
AppDelegate *dataStore = (AppDelegate *)[[UIApplication sharedApplication] delegate];
dataStore.downHUD = [NSNumber numberWithFloat:(float)0];
Both imports the AppDelegate in the .m file but I end up with
Property 'downHUD' not found on object of type 'AppDelegate *'
with the first one.
Anyone that can help me see what's wrong?
I copied and pasted a lot of code into the AppDelegate by mistake, that has been corrected. Is there some sort of link that could got broken?
Maybe there is no such property in your AppDelegate class.
In your AppDelegate.h under interface declaration you need to have
#property (nonatomic, retain) NSNumber* downHUD;
In your AppDelegate.m under implementation declaration you need to have
#synthesize downHUD;
In this manner you define accessors (getter and setter) to access an instance variable called downHUD. This accessors are public and you can do
dataStore.downHUD = ...
Maybe this could be the error. But without AppDelegate code it's difficult to understand what is going on.
Hope it helps.
Edit:
It's no a good strategy to access data within the application delegate. I suggest you to use singletons like singletons-appdelegates-and-top-level.html
Edit 2:
#interface SingletonModel : NSObject {
NSNumber* downHUD_;
}
+ (id)sharedInstance;
#property (nonatomic, retain) NSNumber* downHUD;
#end
#import "SingletonModel.h"
#implementation SingletonModel
#synthesize downHUD = downHUD_;
static SingletonModel *sharedInstance = nil;
+ (SingletonModel *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
-(void)dealloc
{
[super dealloc];
}
+ (id)allocWithZone:(NSZone*)zone {
return [[self sharedInstance] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax;
}
- (oneway void)release {
}
- (id)autorelease {
return self;
}
#end
To set your model:
SingletonModel* model = [SingletonModel sharedInstance];
model.downHUD = ...
To read your model:
SingletonModel* model = [SingletonModel sharedInstance];
NSNumber* n = model.downHUD;
For other info read iphone-code-snippet-the-singleton-pattern and singleton-classes. About Singletons you can find in apple documentation at Cocoa Fundamentals Guide and at Singleton.
Your two view controllers may refer to different AppDelegate code. Even though the Xcode Project Navigator shows only one set of AppDelegate files, and Jump to Definition shows the same AppDelegate class definition in both cases, one of the view controllers may actually have different delegate code.
I had this very problem with a delegate class definition, where some member variables were only available in one view controller but not in the other.
Right-click on each ViewController.m file in the Project Navigator, and use Show in Finder to see whether they are both in the same location as the desired AppDelegate files. If not, move the VC files to the correct location and add them to the project.
If you're using expo this is how to get rid of the bug.
"reactDelegate" was introduced in sdk 44.0.0 so if you're using sdk 43.0.0
here's is how your code should look in your "AppDelegate.m" from line 35 - 46.
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:#"main" initialProperties:nil];
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
If you have imported the header files then it should work. Did you try to clean and re-build your project? You can do that with CMD + Shift + K (or by selecting Clean from the Project menu).

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.

How can I pass a parameter when initializing a UIViewController?

I have two controllers, First- and SecondViewController. I want to share some methods of FirstViewController to use them in my SecondViewController.
This is how I create SecondViewController in FirstViewController:
sms = [[SecondViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:sms];
[self presentModalViewController:navController animated:YES];
I thought of passing the current instance of the FirstViewController to the SecondViewController which extends UIViewController. By default the initWithNibName method of SecondViewController is called.
How do I achieve this in objective-c?
Im not completely sure I understand the problem... as part of the issue has to do with how you are instantiating SecondViewController... posting that code could help.
but to answer your question as you have asked it.... "how to pass FirstViewController into SecondViewController"...
in your SecondViewController.h create your own init method
-(id) initWithFirstViewController:(UIViewController *)theFirstViewController;
and in the .m file...
-(id) initWithFirstViewController:(UIViewController *)theFirstViewController
{
self = [super initWithNibName:#"myNibName" bundle:nil];
self.firstViewController = theFirstViewController; //this assumes you have created this property. Also, do NOT retain the first view controller or you will get circular reference and will secondviewcontroller will leak.
return self;
}
then.. and here is the key.. make sure you are calling the correct init method to instantiate SecondViewContoller
SecondViewController *svc = [[SecondViewController alloc]initWithFirstViewController:self];
now.. having said that.. looking at your SO rating, I have a feeling you already knew this.. and the real question may be... why is the initWithNibName being called when you are not actually calling it explicitly?
Not 100% sure what you are after. The content of your question about sharing methods doesn't seemt o match the question of passing in a parameter at init.
With regard to methods, you can call a method from your parentViewController
if ([self.parentViewController respondsToSelector:#selector(someMethod)]) {
[self.parentViewController someMethod];
}
If you want to pass a parameter in on any class at init, you will want to write a custom init method with any additional parameters you want. That custom method should begin with the appropriate [self init] call. You can even have multiple custom init methods which can be handy.
Here is an example for class that downloads json or xml feeds.
- (id)initWithID:(NSString *)useID delegate:(id)setDelegate urlString:(NSString *)urlString feedIsJSON:(BOOL)feedIsJSON failedRetrySecondsOrNegative:(float)failedRetrySecondsOrNegative refreshSecondsOrNegative:(float)refreshSecondsOrNegative {
if ((self = [super init])) {
// Custom initialization
processing = NO;
self.delegate = setDelegate;
self.feedID = [NSString stringWithFormat:#"%#", useID];
self.feedURLString = [NSString stringWithFormat:#"%#", urlString];
self.isJSON = feedIsJSON;
if (failedRetrySecondsOrNegative>=0.0f) {
retryFailedSeconds = failedRetrySecondsOrNegative;
} else {
retryFailedSeconds = kFailedRefresh;
}
if (refreshSecondsOrNegative>=0.0f) {
refreshSeconds = refreshSecondsOrNegative;
} else {
refreshSeconds = kSuccededRefresh;
}
}
return self;
}
Hope this helps.

obj-c, confusion why can't I add a setter to this class?

Normally I don't have any problem adding a setter method to a class.
However, I'm trying to add to library usage class, which must be causing the problem.
Heres the class I've added it to...
#interface GraphController : TKGraphController {
UIActivityIndicatorView *indicator;
NSMutableArray *data; //I've added
NSString *strChartType; //I've added
}
-(void)setContentType:(NSString*)value; //I've added
#end
#implementation GraphController
-(void)setContentType:(NSString*)value { //I've added
if (value != strChartType) {
[value retain];
[strChartType release];
strChartType = value;
NSLog(#"ChartType=%#", strChartType);
}
}
Heres where I'm getting a warning..
UIViewController *vc = [[GraphController alloc] init];
[vc setContentType:myGraphType]; //Warnings on this line see below
[self presentModalViewController:vc animated:NO];
[vc release];
myGraphType if defined in my constant class.
* Warnings *
warning: 'UIViewController' may not respond to '-setContentType:'
warning: (Messages without a matching method signature
I know the first warning appears when you haven't added the method to the implementation. but I have.
Where am I going wrong ?
UIViewController *vc = [[GraphController alloc] init];
means that vc points to an instance of GraphController but the variable itself is of type UIViewController *, and UIViewController doesn’t declare a -setContentType: method.
Replace that with
GraphController *vc = [[GraphController alloc] init];
to tell the compiler you’re working with a GraphController instance, and it will recognise your -setContentType: method.
You just have to let the compiler know that you're working with a class that it knows responds to the method. You can do it a couple of ways but the easiest one if you just want to eliminate the warning is to cast the object in line before you make the method call.
UIViewController *vc = [[GraphController alloc] init];
[(GraphController *)vc setContentType:myGraphType]; //No warning should appear now.
[self presentModalViewController:vc animated:NO];
[vc release];

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.