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.
Related
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?
There are 3 modifiers: #private, #protected (default) and #public. So if i define a instance variable as private then that should not be accessible from anywhere.
For E.g. -
#interface A {
#private
NSString *a;
}
#property(nonatomic, retain) NSString *a;
Now inside implementation of some other interface/class B-
-(void)getSomeValue {
A *object = [[A alloc] init];
NSString *value = object.a;
.........
}
Here i am able to access instance variable, although i defined that as private.
It is a bit confusing, although when i look into details of this statement, then it is clear that it is calling the getter of a, but then also it seems confusing and it is against the concept of OOPS.
Anyone having any thought on this?
It's not the instance variable you're accessing but the property you declared. Don't declare the property if you do not want the instance variable to be visible outside the class.
#import <Foundation/Foundation.h>
#interface Visibility : NSObject {
#public
BOOL boolPublic;
#protected
BOOL boolProtected;
#private
BOOL boolPrivate;
}
#property (nonatomic, assign) BOOL boolPublic;
#property (nonatomic, assign) BOOL boolProtected;
#property (nonatomic, assign) BOOL boolPrivate;
#end
#implementation Visibility
#synthesize boolPublic;
#synthesize boolProtected;
#synthesize boolPrivate;
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Visibility *visibility = [[Visibility alloc] init];
visibility.boolPublic = YES;
visibility.boolProtected = YES;
visibility.boolPrivate = YES;
// Place following NSLog()'s here
[pool release];
}
Let's try this out
Using the methods you define with #property/#synthesize
NSLog(#"Accessors %d %d %d", visibility.boolPublic, visibility.boolProtected, visibility.boolPrivate);
=> 2012-01-08 17:46:40.226 Untitled[2592:707] Accessors 1 1 1
Accessing #public ivar directly
NSLog(#"Public %d", visibility->boolPublic);
=> 2012-01-08 17:46:40.228 Untitled[2592:707] Public 1
Accessing #protected ivar directly
NSLog(#"Protected %d", visibility->boolProtected);
=> error: instance variable 'boolProtected' is protected
=> NSLog(#"Protected %d", visibility->boolProtected);
=> ^
Accessing #private ivar directly
NSLog(#"Private %d", visibility->boolPrivate);
=> error: instance variable 'boolPrivate' is private
=> NSLog(#"Private %d", visibility->boolPrivate);
=> ^
When you are accessing using dot notation this:
visibility.boolPublic
is equivalent to:
[visibility boolPublic]; // <- This is a method call
Because you set it as a #property and you claim it in header file. The variable you set as a #property will auto generate getter and setter for this variable and they are both public method to get or set it(variable is still private). If you really want to make the property as an private method, you should claim it in .m file and it will become private. You can only use this variable in the .m file.
For example, in your .h file
#interface ClassWithPrivateProperty : NSObject {
#private
NSString* member;
}
- (void) trySettingPrivateProperty;
#end
in your .m file
#import "ClassWithPrivateProperty.h"
#interface ClassWithPrivateProperty ()
#property (nonatomic,retain) NSString* member;
#end
#implementation ClassWithPrivateProperty
#synthesize member;
- (void) trySettingPrivateProperty {
self.member = #"A Value";
NSLog(#"myClass.member = %#", self.member);
}
#end
You can check more detail in Private properties for iPhone Objective-C
Edit:
Thanks for Abizern and Paul's comment, but in fact I got nothing compile error for this program.
I think RIP's question is "Why I set the variable in #private but I can still modify the variable like instance.variable"
The answer is although he set the variable as #private, but claim #property for variable in .h file also provide public methods getter and setter. So he can still get the instance variable use instance.variable. For OOP design pattern you should not expose your internals publicly. So if you want to use a variable privately only in its class and no one know it. And you still want to use getter and setter to access this variable in its class. you should claim #property in .m file like I did above. I claim the #property in .m file, it's a #interface extension(unnamed category). So you can make it "like" private. Because you cannot access this variable from anywhere outside this class. So it's just like a "private #property" that I mention about.
Two useful articles for you Public Properties with Private Setters and Private properties for iPhone Objective-C
hey guys i'm making an app that has 2 views. the first view is where the user inputs the numbers and when they hit calculate button.. its takes them to a new view where the answer is displayed on a textfield. the calculation is handled by a different file. "calc.h " and "calc.m"
this is the main view files (the view where the user enters the numbers )
#import <UIKit/UIKit.h>
#interface test2ViewController : UIViewController {
IBOutlet UITextField *num1; //input number 1
IBOutlet UITextField *num2; // input number2
}
#property (nonatomic,retain) UITextField *num1;
#property(nonatomic, retain)UITextField *num2;
-(IBAction)calculate:(id)sender; //the calculate button
-(IBAction)exit:(id)sender;
#end
the answer is displayed in a different view that shows up when the user hits the calculate button. below is the code for that !
#import "test2ViewController.h"
#import "answer.h"
#import "calculate.h"
#implementation test2ViewController
#synthesize num1,num2;
-(IBAction)calculate:(id)sender{
calculate *testclass = [[calculate alloc]init];
answer *view = [[answer alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:view animated:YES];
int i = [[num1 text] intValue];
testclass.number1 = i;
int j = [[num2 text] intValue];
testclass.number2 = j;
[testclass calc];
}
".h" file of the view that displays the answer
#import <UIKit/UIKit.h>
#interface answer : UIViewController {
IBOutlet UITextField *text;//textfield to display answer
}
#property(nonatomic,retain) UITextField *text;
-(IBAction)back:(id)sender;
#end
".m" file
#import "answer.h"
#import "test2ViewController.h"
#import "calculate.h"
#implementation answer
#synthesize text;
-(IBAction)back:(id)sender{
test2ViewController *view = [[test2ViewController alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:view animated:YES];
}
the next is an objective c class file that does the calculation. it has one function that does the calculation and here is the ".h" and ".m" file
".h"
#import <Foundation/Foundation.h>
#interface calculate : NSObject {
int number1;
int number2;
NSString *ans;
}
#property int number1;
#property int number2;
#property (nonatomic , retain) NSString *ans;
-(void)calc;
#end
".m"
#import "calculate.h"
#import "answer.h"
#import "test2ViewController.h"
#implementation calculate
#synthesize number1,number2,ans;
-(void)calc{
int i = number1 + number2;
answer *ans1 = [[answer alloc]init];
ans = [NSString stringWithFormat:#"%d",i];
ans1.text.text = ans;
}
#end
so as you can see the above function calculates the answer..puts it into a string and sets that to the textfield. but the textfield doesn't show anything..so the problem here is that i cannot access the textfield even though i created an object from it....
Im a bit confused to what your trying to accomplish, do you want to use an NSString or the text UITextField in another class? If thats the case give the string that is carrying whatever you want to be displayed a #property, then set whatever you want the strings value to it, next import the calc.h (#import "calc.h") in the second class, then in the interface create this calc *getString; create a #property for that, #synthesize it. Then to get the value of the string from calc do something like this getString.SomeStringName, now you are able to do whatever you want with it.
I think this is what you want? if not feel free to comment. Good Day :)
Edit: Im going to give you an example because this is a bit confusing the way i wrote it lol
So here is your calc.h file, also remember im typing this online and not in xcode, so if i spell something wrong or make a simple mistake, thats why:
#interface calc : UIViewController {
NSString *answer;
}
#property (nonatomic, retain) NSString *answer;
#end
Your .h could have more
Now lets hop into your .m
#implementation calc
#synthesize answer;
//do all the work to get the answer, once you have it do this
[answer retain];
//load your new view controller
Lets hop into your other view controller that will be loaded
this is .h file of it
#import "calc.h"
#interface secondController : UIViewController {
calc *getAnswer;
}
#property (nonatomic, retain) calc *getAnswer;
#end
Then go to your .m
#implementation secondController
#synthesize getAnswer;
-(void)viewDidLoad{
WhateverYouWantTheStringToBeSetTo.text = getAnswer.Answer;
}
This should then grab the string from the other controller and allow you to use it in this one..
Hope this helps :)
The problem is that your "ans" UIViewController did not load yet.
The most standard way to do this is to give your UIViewController "ans" a #property with the result. Then in the "ans" viewDidLoad method, set the text field to the appropriate value.
I try to learn protocol of objective C.
I write two files, the first one is FirstViewController.h, and in which there is a protocol "print". I declare FirstViewController class in successViewController with the delegate method "print".
The question is why the console output is "C". Why I can not get the "B" output? Why the protocol method did not perform?
#import <UIKit/UIKit.h>
#import "FirstViewController.h"
#interface successViewController : UIViewController <FirstViewControllerDelegate> {
}
#end
#import "successViewController.h"
#import "FirstViewController.h"
#implementation successViewController
- (void)viewDidLoad {
FirstViewController *firstViewController= [[FirstViewController alloc] init];
firstViewController.delegate=self;
NSLog(#"C");
[super viewDidLoad];
}
-(void) print{
NSLog(#"B");
}
#end
#import <Foundation/Foundation.h>
#class FirstViewController;
#protocol FirstViewControllerDelegate <NSObject>
- (void) print;
#end
#interface FirstViewController : NSObject {
id <FirstViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id <FirstViewControllerDelegate> delegate;
#end
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize delegate;
#end
Because you never call the print method. Where were you expecting it to be called?
Objective-C protocols allow you to specify that a class is capable of performing certain actions. In your example, the successViewController is declared FirstViewControllerDelegate, meaning it is capable of handing the duties required by FirstViewController of its delegate. It is more of a programming contract between classes, one that can be verified by the compiler.
As a side note, classes in Objective-C should always start with a capital letter, methods should always start lowercase. Your FirstViewController follows this rule, but the successViewController does not.
You need to call the method you want to use.
[successViewController print];
You never call the delegates print method. A delegate can not read your mind and automagically call stuff. Lets take a small example how how delegates are supposed to work.
Assume we have a class called Delay, the only thing it do is to wait for a time when start is called, and then tell it's delegate that it has waited. Optionally the delegate can tell the Delay how long to wait, if the client do not care, a 1 second delay is assumed.
Some rules:
First argument of all delegate methods should be the sender itself, never have delegate methods with no arguments.
Delegate method name should include one of the words:
will - if method is called before something unavoidable occurs. Example applicationWillTerminate:
did - if method is called after something has occurred. Example scrollViewDidScroll:
should - if the method return a BOOL to signal if something should occur. Example textFieldShouldClear:
Name the method to tell what has occurred, not what you expect the delegate to do.
Only exception is if the client is expected to return something, then that something should be part of the name. Example: tableView:editingStyleForRowAtIndexPath:
Here is the simple definition and implementation. Notice that I do not even check if the delegate has been set, since calling methods on nil is just ignored anyway.
// Delay.h
#protocol DelayDelegate;
#interface Delay : NSObject {
#private
id<DelayDelegate> _delegate;
}
#property(nonatomic, assign) id<DelayDelegate> delegate;
-(void)start;
#end
#protocol DelayDelegate <NSObject>
#required
-(void)delayDidComplete:(Delay*)delay;
#optional
-(NSTimeInterval)timeIntervalForDelay:(Delay*)delay;
#end
// Delay.m
#interface Delay
#synthesize = delegate = _delegate;
-(void)start {
NSTimeInterval delay = 1.0;
if ([self.delegate respondsToSelector:#selector(timeIntervalForDelay:)]) {
delay = [self.delegate timeIntervalForDelay:self];
}
[self performSelector:#selector(fireDelay) withObject:nil afterDelay:delay];
}
-(void)fireDelay {
[self.delegate delayDidComplete:self];
}
#end
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.