How can I simply change a class variable from another class in ObjectiveC? - iphone

I simply want to change a variable of an object from another class. I can compile without a problem, but my variable always is set to 'null'.
I used the following code:
Object.h:
#interface Object : NSObject {
//...
NSString *color;
//...
}
#property(nonatomic, retain) NSString* color;
+ (id)Object;
- (void)setColor:(NSString*)col;
- (NSString*)getColor;
#end
Object.m:
+(id)Object{
return [[[Object alloc] init] autorelease];
}
- (void)setColor:(NSString*)col {
self.color = col;
}
- (NSString*)getColor {
return self.color;
}
MyViewController.h
#import "Object.h"
#interface ClassesTestViewController : UIViewController {
Object *myObject;
UILabel *label1;
}
#property UILabel *label1;
#property (assign) Object *myObject;
#end
MyViewController.m:
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
[myObject setColor:#"red"];
NSLog(#"Color = %#", [myObject getColor]);
[super viewDidLoad];
}
The NSLog message is always Color = (null)
I tried many different ways to solve this problem, but no success.
Any help would be appreciated.
Thanks for the help so far.
I modified the code as follow, but it still doesn't work as it should.
MyViewController.h:
#import <UIKit/UIKit.h>
#import "Object.h"
#interface MyViewController : UIViewController {
Object *myObject;
}
#property (nonatomic, retain) Object *myObject;
#end
MyViewController.m:
#import "MyViewController.h"
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
Object *myObject = [Object new];
myObject = 0;
[myObject setColor:#"red"];
NSLog(#"color = %#", myObject.color);
[super viewDidLoad];
}
If I do it like this, NSLog returns color = null (and I think myObject is only visible in viewDidLoad). How can declare myObject and make it visible in MyViewController?
I stripped down my Object class to
Object.h:
#interface Object : NSObject {
NSString *color;
}
#property(nonatomic, retain) NSString *color;
#end
Object.m:
#import "Object.h"
#implementation Object
#synthesize color;
#end
I wasn't able to define an object myObject in ViewDidLoad so that I can access its properties from the whole ViewController class? What did I miss?
Side question: Why do I have to set myObject to 0?

You're declaring a property, then explicitly declaring the accessors in Object.h. You only need to do one or the other - they mean the same thing (well, almost - you'll have color instead of getColor)
To implement the property in Object.m you should use #synthesize color. The explicit implementations, again, are then redundant (unless they do anything extra).
The explicit setColor implementation in Object.m is calling the property - which you are implementing explicitly, so I would have expected you to get an infinite recursion here.
MyViewController.m should probably synthesize label1, since you declare the property in the header (although it's not being used in your snippet).
[myObject getColor] is calling the color property, which you declared but did not synthesize. If you had explicitly implemented it as color it would have picked that up - but it won't match getColor (which is fortunately as that would have led to an infinite recursion again.
I don't see anywhere where you create your myObject instance. If you don't it will be nil and methods called on it (including property accesses) will return 0 or nil.
I suspect (6) is the cause of your issue, but the others need to be addressed too. Make sure you read up on property syntax.

Related

wrong delegate declaration

Lets assume I have a class ClassA
header:
#interface ClassA : NSObject
- (id)initWithDelegate:(id)delegate;
#end
implementation:
#interface ClassA ()
{
NSObject *_delegate;
}
#end
#implementation
- (id)initWithDelegate:(id)delegate
{
self = [super init];
if( self )
{
_delegate = delegate;
}
return self;
}
#end
Since I skipped the #property definition my delegate declaration defaults to strong? So this code is wrong because it will cause a leak, or does my delagate declaration default to weak?
You do have to qualify that ivar as __weak. The default for an ivar is strong.
Otherwise, as you already know, you risk a retain cycle with delegates.
BTW, the convention here is 'id' rather than NSObject *.
It’s best to write the code in a way that makes this explicit:
#interface ClassA : NSObject
#property(weak) id delegate; // or #property(weak, readonly)
#end
#implementation ClassA
- (id)initWithDelegate: (id) delegate
{
self = [super init];
_delegate = delegate;
return self;
}
#end
By default, you instance variable would be strong.
You are correct, this will cause ARC to retain the _delegate, ie make a "strong" reference. If you want to create a weak reference without declaring a #property, you can use
#interface ClassA ()
{
__weak id _delegate;
}
#end

EXD_BAD_ACCESS passing data back to delegate

I'm a relatively new iPhone developer and am making great progress building my 2nd iPhone app. In the app I'm building now I'm doing some code separation with some protocols and delegates so that I car re-use some of my code in a variety of places throughout my code.
Here's what I want to happen:
CITRootViewController creates an instance of a CITReportCreator class, passing itself as a property so that the reportCreator can open additional view controllers and such.
CITReportCreator class is declared as implementing the CITImageCaptureDelegate protocol, which is declared in the CITImageCaptureViewController file.
CITImageCaptureViewController defines the delegate protocol and has a method that passes back data and references to the child view controller so that CITReportCreator can interact with it's data, close the related XIB, etc.
I believe I'm getting the delegate and protocol established correctly, and verified that my 'delegate' object still contains data when it is called, but I'm getting a EXC_BAD_ACCESS method when my view controller tries to pass data back to the delegate in this line of code:
[self.delegate childViewControllerDidFinish:self];
Here's a good portion of the rest of my code. I had this working by using CITRootViewController as my delegate instead of the CITReportCreator class, but now that I'm separating the code, something has broke.
CITReootViewController.m (the view controller that calls the Report Creator)
//create a nrew report
-(IBAction)createReport:(id)sender {
CITReportCreator *report = [CITReportCreator alloc];
[report createNewReport:self];
}
CITReportCreator.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "CITImageCaptureViewController.h"
#interface CITReportCreator : NSObject <CITImageCaptureDelegate>
#property (strong, nonatomic) NSArray *imageList;
#property (nonatomic) NSInteger imageIndex;
-(int) createNewReport:(UIViewController *)parent ;
//Delegate Methods
-(void) childViewControllerDidFinish:(UIViewController*)viewController;
#end
And CITReportCreator.m
#import "CITReportCreator.h"
#implementation CITReportCreator
{
UIViewController *parentController;
}
#synthesize imageList;
#synthesize imageIndex;
-(int) createNewReport:(UIViewController *)parent
{
//store a reference to the parent view controller
parentController = parent;
// init code....
//head to the first image capture view
[self startImageCapture];
return 0;
}
-(int)startImageCapture
{
//pull the image name from the array of images
NSString *imageName = [imageList objectAtIndex:imageIndex];
//prep the image capture controller
CITImageCaptureViewController *capture = [[CITImageCaptureViewController alloc] initWithNibName:#"CITImageCaptureViewController" bundle:nil];
//Assign the capture controller's delegate
capture.imageName = imageName;
capture.delegate = self;
//Display the capture controller
[parentController presentModalViewController:capture animated:YES];
return 0;
}
//a break point set here never gets hit.
-(void) childViewControllerDidFinish:(UIViewController*)viewController;
{
[viewController dismissModalViewControllerAnimated:YES];
}
#end
And finally, the CITImageCaptureViewControllers
CITImageCaptureViewController.h
#import <UIKit/UIKit.h>
#protocol CITImageCaptureDelegate <NSObject>
-(void) childViewControllerDidFinish:(UIViewController*)viewController;
#end
#interface CITImageCaptureViewController : UIViewController
{
id<CITImageCaptureDelegate> delegate;
}
#property (nonatomic,assign) id<CITImageCaptureDelegate> delegate;
#property (nonatomic, assign) NSString *imageName;
//continue button pressed method
-(IBAction)continueButtonPressed:(id)sender;
#end
And the .m file
#import "CITImageCaptureViewController.h"
#interface CITImageCaptureViewController ()
#end
#implementation CITImageCaptureViewController
#synthesize navItem;
#synthesize imageName;
#synthesize delegate = _delegate; //i think this may be part of the problem
//cutting out initWithNibName, viewDidLoad, etc...
- (IBAction)continueButtonPressed:(id)sender
{
[self.delegate childViewControllerDidFinish:self];
}
#end
I find nothing with delegates and protocols all that simple, but I'm guessing I'm missing a small change somewhere. Can you help me head in the right direction?

Override #synthesize method?

I have one class called dog and another class called cat.
Dog has an variable, "name" declared with #property in the .h file.
In the cat class, I have set the name by using the command, myDog.name = "buster", after creating the variable "myDog" of type dog.
I would like to do additional operations when the name is set by overriding the set method normally created by the #synthesize command.
How can I do that? Thanks for the help!
All you have to do is leave the #synthesize then create whichever methods you want to be custom. Example:
In .h
#property(nonatomic, retain)NSString *Bob;
In .m
#synthesize bob;
-(void)setBob:(NSString *)bobValue{
[bobValue retain];
[bob release];
bob = bobValue;
//your custom stuffs here
}
This has been pretty much answered on SO already - see Objective-C synthesize property name overriding for details. In particular, #Dev Kanchen's answer which includes example code.
You cannot override (and call it within) a synthesized method from within the very same class.
You can however override it from a subclass (or rather: synthesize it in an abstract superclass).
If you simply want to perform additional (vs. different) operations upon property change I would use KVO by simply adding each dog as observer to its own "name" property in -(id)init;.
Edit:
There is a way to add additional logic to synthesized methods from within the same class:
Define a private intermediate property in a class extension.
I've attached source code for a class which uses synthesized properties and takes care(sic!) of keeping the dog's owner in sync with its own identity.
Dog.h:
#import <Foundation/Foundation.h>
#interface Dog : NSObject {
#private
NSString *name;
NSString *owner;
}
#property (nonatomic, readwrite, retain) NSString *name;
#property (nonatomic, readwrite, retain) NSString *owner;
#end
Dog.m:
#import "Dog.h"
#interface Dog ()
#property (nonatomic, readwrite, retain) NSString *primitiveName;
#end
#implementation Dog
#dynamic name;
#synthesize primitiveName = name;
#synthesize owner;
- (id)init {
if ((self = [super init])) {
name = #"Snowy";
owner = #"Tintin";
}
return self;
}
- (void)dealloc {
[super dealloc];
}
- (NSString *)name {
return self.primitiveName;
}
- (void)setName:(NSString *)aName {
self.primitiveName = aName;
if ([aName isEqualToString:#"Snoopy"]) {
self.owner = #"Charlie Brown";
}
else if ([aName isEqualToString:#"Snowy"]) {
self.owner = #"Tintin";
}
}
- (NSString *)description {
return [NSString stringWithFormat:#"<%# name:'%#' owner:'%#'>", [self class], self.name, self.owner];
}
#end
Test:
Dog *dog = [[Dog alloc] init];
NSLog(#"%#", dog);
dog.name = #"Snoopy";
NSLog(#"%#", dog);
dog.name = #"Snowy";
NSLog(#"%#", dog);
Result:
<Dog name:'Snowy' owner:'Tintin'>
<Dog name:'Snoopy' owner:'Charlie Brown'>
<Dog name:'Snowy' owner:'Tintin'>

How can I execute code from another methods property

Sorry if the question is not to clear, this is what im trying to do. I have an object, a delegate and a view controller.
Object pseudo-code
#interface Car: NSObject {
UIColor *color;
}
#property (assign)UIColor *color;
- (void) setColor(UIColor col);
#end
#implementation Car
#synthetize color;
// i know that synthesize makes this function redundant.
// I just used it to demonstrate
// the need to access an instance method.
- (void) setColor(UIColor col)
{
color = col;
}
#end
delegate code
#interface myDelegate: UIApplicationDelegate {
Car *car;
UIViewController *theView;
}
#property (assign)Car *car;
#end
#implementation myDelegate
#synthesize car;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
theView = [[MyViewController alloc]init];
return YES;
}
#end
View pseudo Code
#interface MyViewController: UIViewController {
MyDelegate *appDelegate;
}
#property (retain) MyDelegate *appDelegate;
#end
#implementation MyViewController
#synthesize appDelegate;
- (void)viewDidLoad {
self.appDelegate = (MyDelegate*)[[UIApplication sharedApplication] delegate];
/// THIS IS MY ISSUSE!
[self.appDelegate.car setColor(UIColor);
}
#end
Can anyone explain or point me to where i can understand why [self.appDelegate.car setColor()] gives me a compile error that reads "Unknown component setColor of a property".
Im sure there is a way to do this in objective C as i would do it in python, java or other OO language.
Any help would be greatly appreciated
Cheers
Rudy
You are not using UIColor as a pointer.
Try using UIColor * instead of just UIColor and the compiler will stop complaining
First of all, the Car class has problems. The color property should be defined as retain, not assign. assign is generally for non-object type properties, such as an NSInteger, BOOL, int, etc., and for a special case of objects that shouldn’t be retained because they’d create retain cycles. Also, - (void)setColor(UIColor col); is not a valid method name, as it is written as if it were a function. In Objective-C, each parameter is preceded by a colon :.
For example, take the following method:
- (void)setBodyColor:bodyColor lowerColor:lowerColor upperColor:upperColor;
While that is technically a valid method signature, it is generally written differently to make its usage more clear. As it’s defined above, each parameter is of type id, which is a generic object type. To make things clearer, you cast each argument to the type of objects they represent:
- (void)setBodyColor:(UIColor *)bodyColor
lowerColor:(UIColor *)lowerColor
upperColor:(UIColor *)upperColor;
In addition to being defined incorrectly, it’s also superfluous since defining a read-write property named color implies that a -setColor: method will be defined. The code would look like this:
#interface Car: NSObject {
UIColor *color;
}
#property (retain) UIColor *color;
#end
#implementation Car
#synthetize color;
- (void)dealloc {
[color release];
[super dealloc];
}
// If you need to override a method, that’s fine
- (void) setColor:(UIColor *)aColor
{
[aColor retain];
[color release];
color = aColor;
// do more stuff
}
#end
On to your delegate, it also has problems. First, myDelegate is defined as a subclass of UIApplicationDelegate, which is not even a class: it’s a protocol (or interface) that other objects can conform to. The car property should also be defined as retain, since it’s an object that your app delegate owns. Here, theView (which should likely be renamed to something like theViewController) should be typed as MyViewController to make it more clear.
#interface MyDelegate : NSObject <UIApplicationDelegate> {
Car *car;
MyViewController *theView;
}
#property (retain) Car *car;
#end
#implementation MyDelegate
#synthesize car;
- (void)dealloc {
[car release];
[theView release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
theView = [[MyViewController alloc] init];
return YES;
}
#end
The MyViewController class has problems in that the appDelegate is defined as retain when it should likely be assign. The app delegate itself is creating the view controller using alloc/init, meaning the app delegate “owns” the view controller. The view controller shouldn’t retain the app delegate because that would create a retain cycle (see Retain Cycles).
MyViewController.h
// forward declaration
#class MyDelegate;
#interface MyViewController: UIViewController {
MyDelegate *appDelegate; // non-retained
}
#property (assign) MyDelegate *appDelegate;
#end
MyViewController.m
#import "MyViewController.h"
#import "MyDelegate.h"
#implementation MyViewController
#synthesize appDelegate;
- (void)viewDidLoad {
self.appDelegate = (MyDelegate*)[[UIApplication sharedApplication] delegate];
[self.appDelegate.car setColor:[UIColor clearColor]];
/// THIS IS MY ISSUSE!
// [self.appDelegate.car setColor(UIColor);
}
#end

iPhone: initialize object in controller

I am very new to objective-c and having a problem to initialize an object in view controller. The problem I am having is that when setTemp method is called, "0" is printed on the screen instead of the value of cTemp I would like it to be. Can anyone help me on this problem?
Below are excerpts of the code I have.
SJT.h
#import <Foundation/Foundation.h>
#import <stdlib.h>
#interface SJT : NSObject {
int cTemp;
}
- (int) newTemp;
#end
SJT.m
#import "SJT.h"
#implementation SJT
- (int) newTemp
{
cTemp = 25 + rand() % 8;
return cTemp;
}
#end
SJTViewController.h
#import <UIKit/UIKit.h>
#class SJT;
#interface SJTViewController : UIViewController {
IBOutlet UILabel *temp;
SJT *sjt;
}
#property (retain, nonatomic) UILabel *temp;
#property (retain, nonatomic) SJT *sjt;
- (IBAction) setTemp: (id) sender;
#end
SJTViewController.m
#import "SJTViewController.h"
#import "SJT.h"
#implementation SJTViewController
#synthesize temp;
#synthesize sjt;
- (IBAction) setTemp: (id) sender
{
NSString *tempText = [[NSString alloc] initWithFormat:#"%d",sjt.newTemp];
temp.text = tempText;
[tempText release];
}
.
.
.
#end
The problem is that you're mistaking property syntax for a method call; i.e.
sjt.newTemp
would become a call to [sjt newTemp]. Which happens to be exactly what you want, except that you have not specified in your header/implementation that there actually is a property called newTemp.
So, in this scenario what you want to do is either a) define the property in the header:
#property(nonatomic, readonly) int newTemp;
or b), just call the method newTemp:
[sjt newTemp]
Are you certain that sjt is not nil? You don't provide the code where and instance of SJT is constructed. In Objective-C you can call a method on a nil reference without error, and if you do so on a method that returns an int it will return 0.
So sjt.newTemp will return 0 if sjt is nil.
Both Jacob and teabot have pointed out valid possible reasons -- which one is correct (or both!) depends on pieces of code we can't see in your post.
Based on what you've written so far, you might not be thinking of newTemp as a property, but more as a function call, so I would suggest changing your code to:
- (IBAction) setTemp: (id) sender {
int tempInt = [self.sjt newTemp];
self.temp.text = [NSString stringWithFormat:#"%d", tempInt];
}
which is functionally equivalent. Note the convenience constructor stringWithFormat: returns an autoreleased object, which is then retained by the retain property text of the temp UILabel.
The other thing to double-check in your code is that self.sjt is not nil, which is exactly what teabot said. Objective-C returns 0 on method calls invoked on a nil pointer.