I am trying to use a variable integer throughout multiple methods in my view controller. The secondsLeft variable works fine, but the otherNumber variable won't work. I get the error: initializer element is not a compile-time constant. Any ideas on how I am supposed to do this? THank you!
#interface ViewController ()
#end
#implementation ViewController
#synthesize countDown,Timerlbl;
int secondsLeft = 500;
int otherNumber =[(AppDelegate *)[UIApplication sharedApplication].delegate otherNumber];
The problem is that you have declared otherNumber as a global variable and the compiler expects the initial assignment to be a compile-time constant. [delegate otherNumber] results in a selector invocation and this is not a compile-time constant.
The solution is to move the assignment into code. For example:
- (id)init
{
self = [super init];
if(self) {
otherNumber = [(AppDelegate *)[UIApplication sharedApplication].delegate otherNumber];
}
return self;
}
As another note, global variables are generally inadvisable in Objective-C. #property values are generally more recommended. Not only that, your ViewController class now has a dependency with your AppDelegate. Since your AppDelegate most likely is the one responsible for instantiating your ViewController, consider having it inject in the value of otherNumber. For example:
#interface ViewController ()
#property (nonatomic, assign) int otherNumber;
#end
- (id)initWithSomeNumber:(int)otherNumber
{
self = [super init];
if(self) {
self.otherNumber = otherNumber;
}
return self;
}
I assume that AppDelegate is the name of your app delegate class?
Have you tried adding an import for your AppDelegate, like this...
#import "AppDelegate.h"
#interface ViewController ()
You can't declare a variable like this because the compiler can't create an instance of AppDelegate and ask it what the value of otherNumber should be.
Depending on how it's being used, it might be better not to define the otherNumber variable at all, and instead retrieve it from AppDelegate each time it is used. This might mean a little more typing, but it does mean you'll always get the latest correct value of otherNumber
Also, it's a good idea in general to use NSInteger instead of int when defining integer variables.
Related
i have "classmap.m" and annotation.m i have a value of coordinates in "classmap.m" and i need to assign a value in the other class annotation.m.
ex:
class1.m
double start_long;
i want to give pass the value in another one class (annotation.m)
annotation.m
annotation.longitude=Start_long;
how can i do that please give some examples is there.
thanks in advance
A better, more efficient, effective and cleaner way is to use Singleton Pattern. A good approach is to keep AppDelegate cleaner and avoid keeping global variables there. Always try to use Singleton classes and objects to keep global variables.
If both classmap.m and annotaion.m are inherited from NSObject then it's simple annotation:classmap . will give access to the properties of classmap
ClassMap
#interface classmap : NSObject
#property double longitude;
#end
#import "classmap.h"
#implementation classmap
#synthesize longitude;
#end
Annoataion
#interface annotation : classmap
#property double start_long;
#end
#import "annotation.h"
#implementation annotation
#synthesize start_long;
#end
Now the assigning can be done easily in annotation.longitude=Start_long the place you need
Take the variable in the Appdelegate and access it anywhere in the project .
Access it like
Assign Value
AppDelegate *app = [[UIApplication sharedApplication]delegate];
appd.start_long = -17.002// assign some value here
Read Value
AppDelegate *app = [[UIApplication sharedApplication]delegate];
double dVal = appd.start_long ;
The Singleton pattern is a weapon which should be used sparingly as it makes a concrete dependancy on the ClassMap object for everything which uses it.
While using a Singleton will achieve what you want right now which is access to a property in ClassMap but you set yourself up for future coding issues.
What happens when you have multiple ClassMap instances for example?
Singletons are better suited to things which do universal jobs. Things which are tools. e.g [NSUserDefaults standardUserDefaults] or [NSFileManager defaultManager]
A different solution is to use Dependancy Injection which creates a direct connection between the object Annotation which needs the ClassMap object.
In brief ClassMap declares a property
#property double start_long;
you pass the ClassMap object to the Annotation object when you instantiate.
Annotation.h
#interface Annotation:NSObject
-(instancetype)initWithClassMap:(ClassMap *)amap;
#end
and…
Annotation.m
#interface Annotation() {
ClassMap *_map;
}
#end
#implementation Annotation
-(instancetype)initWithClassMap:(ClassMap *)amap {
self = [super init];
if(self) {
_map = amap;
}
return self;
}
-(void)doSomething {
self.longitude = _map.start_long;
}
#end
Another method is to use delegation.In your classmap.m declare
#protocol classmapDelegate <NSObject>
-(void)didchangeCoordinateValue:(double)longitude;
#end
annotation should confirm to this protocol and when ever the value in classmap is changed, you could get the event tin Annotation class.
Since xcode 4.4 you don't need to #synthesize properties anymore (see here), the compiler does it for you. So, why does the compiler complain
use of the undeclared identifier _aVar
in my viewDidLoad method of ViewControllerSubclass:
#interface ViewController : UIViewController
#property (assign, nonatomic) int aVar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
#interface ViewControllerSubclass : ViewController
#end
#interface ViewControllerSubclass ()
#property (assign, nonatomic) int aVar;
#end
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
If I move everything to the one file instead of 4 separate files for the respective interfaces and implementations, the compiler instead complains that _aVar is private. But _aVar should have been automatically synthesized in my ViewControllerSubclass.
Still keeping everything in 1 file, if I move the initial property declaration to a class extension:
#interface ViewController ()
#property (assign, nonatomic) int aVar;
#end
The build still fails saying that _aVar is private.
If I go back to the 4 file setup for the respective interfaces and implementations xcode builds without even a warning.
If I then run the code:
[[[ViewControllerSubclass alloc] init] view];
the log statements in the above examples print out the following:
Super value: 0
Subclass value: 5
It makes sense that NSLog(#"Super value: %d", _aVar); produced a result of 0 because this variable is supposed to be private to the superclass. But then, why does NSLog(#"Subclass value: %d", _aVar); produce a result of 5??
This is all very odd.
You are confusing several different issues, and I'm somewhat confused when you talk about jumping between files and you don't specify where your errors are happening.
Anyway, there is the issue of instance variable visibility. If you declare your iVars within the interface scope, they are, by default, protected.
#interface Foo : NSObject {
int protectedInt;
#private
int privateInt;
#public
int publicInt;
}
#end
When you synthesize iVars, the instance variables themselves are private, unless you explicitly specify them.
Methods will always fire on the most derived implementation.
Now, when you call this...
[[[ViewControllerSubclass alloc] init] view];
You will allocate a subclass, initialize, and cause the view to be loaded. This code will execute...
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
The first thing it does is call the base class implementation...
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
Of course, it calls super, but that part's not important here. The next line assigns 5 to self.iVar. But, which iVar? It calls the property setter method on this object. What type is this instance? It's a ViewControllerSubclass. Since you have given both your base class and its subclass the same name (and declared the property as part of the class extension), they each have their own private-scope instance variable .
However, a method is called on the most derived implementation. Thus, self.iVar will set the instance variable of the subclass. The instance variable for the base class remains unchanged.
When you NSLog the value, you are accessing the private instance variable of the base class, which has not been changed.
Now, after the base class viewDidLoad finishes, we get the code running for the subclass. It logs the value of its private instance variable, which was changed as a result of the base class calling the property setter. So, it will now print it's value, which is 5.
When you make the superclass declaration public, the compiler won't attempt to re-synthesize the property; it assumes that's been taken care of in the superclass. Thus, _aVar is not in scope anywhere in the subclass. It's private anyway, so even when you put them all in the same file that's why you see those errors.
However when you make the superclass property declaration inside the class extension, the compiler will auto-synthesize the property for both the superclass and the subclass. This ends up with both classes having private instance variables _aVar (with two distinct addresses). However, when the superclass viewDidLoad method sets the property, the method invokes the subclass's accessors, which set the value of the subclass's private _aVar variable, and not the superclass's. So that explains why you see the superclass value not changing.
Hope this helps!
I just tested your setup and could replicate your error. I came to the following conclusion:
You need to declare your #property in a .h file. If you want a private variable, declare it in .m in the category #interface (the one with the parentheses).
This is an objective-c problem. I have created a subclass person of NSObject with parameters 'height' and 'weight', with property and synthesize in a file called Person.h that contains both interface and implementation.
I want to import Person.h into my viewcontroller.m and create person objects and alter them using 2 IBActions.
-(IBAction)alterperson_1{
person *bob = [person alloc]init];
bob.height = 72;
bob.weight = 200;
}
-(IBAction)alterperson_2{
bob.height = 80;
bob.weight = 250;
}
This arrangement does not work because the method alterperson_2 can't find Bob because it is a local variable to alterperson_1. My question is how and where in viewcontroller.m do I allocate Bob as a person so that his attributes can be altered by both IBActions.
I have tried allocing in viewdidload as well as in the initwith nibname methods. It did not work. I have also tried in the implementation{ } of viewcontroller.m but that doesn't work either because Bob's allocation is not a compile time constant.
Thanks!
Update With Code
So, I have the Person.h file importing properly now (thanks Robotnik), and am able to create instances of Person throughout ViewController.m -- however, my created instance *bob does not seem to retain values for its properties (see comments by NSLog statements in the code). I think this is an initialization issue, but I have no idea where to initialize. Currently, I get a warning when initializing in viewDidLoad. How do I get bob.weight to print 200 when my IBAction is called, instead of the 0 I currently get? Thanks.
// Person.h
#import <Foundation/Foundation.h>
#interface Person : NSObject{
int weight;
int height;
}
#property int weight, height;
#end
end Person.h
//Person.m
#import "Person.h"
#implementation Person
#synthesize weight, height;
#end
end Person.m
//ViewController.h
#import <UIKit/UIKit.h>
#import "person.h"
#interface ViewController : UIViewController{
}
#property Person *bob;
-(IBAction)persontest:(id)sender;
#end
end ViewController.h
//ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize bob;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Person *bob = [[Person alloc]init]; // this causes a local declaration warning, if I remove this code, however, it still doesn't work
bob.weight = 100;
NSLog(#"viewDidLoad bob's weight, %i", bob.weight); // this will print 100, but only because I made the local initialization. The value is lost once the viewDidLoad Method ends.
}
-(IBAction)persontest:(id)sender{
bob.weight = bob.weight + 100;
NSLog(#"IBAction bob's weight %i", bob.weight); // this prints 0, probably because value is nil. How can I make it print 200?
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
end ViewController.m
You'll need to declare Bob in your ViewController.h if you want him to be accessible across multiple methods. You can then initialise him in viewDidLoad
#interface ViewController
{
Person *bob;
}
-(IBAction)alterperson_1;
-(IBAction)alterperson_2;
#end
You mentioned you wanted to instantiate multiple people. In that case you may want to keep multiple Person objects in an NSMutableArray or similar. This should still be declared in the ViewController.h in order to be accessible in multiple methods. You can then use the method addObject: to add people to the array. Here is an example of an array, storing strings.
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:#"Dog"];
[stringArray addObject:#"Cat"];
You seem to be confusing declaration of a variable with allocation of a variable. You're also not using properties properly.
Declaration of a variable is done like this:
Person *bob;
That's it. If you put this line in your #interface section, or in {braces} at the top of your implementation section, then this becomes an instance variable, any time you use bob in the rest of your class it will know that you are talking to a person. So, in your viewDidLoad, you can now do this:
bob = [[Person alloc] init];
And it knows you are referring to the instance variable. In your current code, you have Person * in front of this line, which, as the compiler is telling you, is declaring a local variable with the name bob, and therefore hiding your instance variable, so you are not changing your instance variable at all, so there is no value in it later.
Looking at the nature of this question, and your comments, I would strongly advise reading some objective-c introductory texts before proceeding much further. You can ask questions here but SO is not really the place to learn a language - most answerers will assume that you know the language basics.
I'm fairly new to programming in Objective-C. While I have been able to find my way, there now is an issue I cannot solve, which is either caused by a mistake I made or because I have a fundamental misunderstanding about classes.
Essentially, I want one class to change a variable (or object) in another class. Here is the code I have:
// LocationManager.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface LocationManager : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *locationByCustomLocation;
}
#property (nonatomic, retain) CLLocation *locationByCustomLocation;
#end
Of course, there's a corresponding implementation file: LocationManager.m. It synthesizes the locationByCustomLocation variable.
The point is that from another class, I'd like to manipulate the locationByCustomLocation variable.
// viewCustomLocation.h
#import <UIKit/UIKit.h>
#interface viewCustomLocation : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tblLocation;
UITableViewCell *cell;
}
--
//viewCustomLocation.m
#import "viewCustomLocation.h"
#import "LocationManager.h"
#class LocationManager;
#implementation viewCustomLocation
#synthesize tblLocation;
#synthesize cell;
// some view related selectors here, but it boils down to this one:
- (void)dismissView:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
LocationManager *locationManager = [[LocationManager alloc] init];
// I made sure with NSLog that the customLoc variable contains the expected data
CLLocation *customLoc = [[CLLocation alloc] initWithLatitude:place.coordinate.latitude longitude:place.coordinate.longitude];
[locationManager setLocationByCustomLocation:customLoc];
}
Now, if I use NSLog in LocationManager.m to see what's in the LocationByCustomLocation variable, I would expect the same data as in customLoc. Instead, the variable still seems empty.
I think the problem is that I created a copy of the LocationManager class, thus filling the LocationByCustomLocation variable in the copied class, rather than the original one, which is what I want. I can't figure out how to talk to the original LocationManager class.
I know of a few ways to work around this issue, but I would like to know how to achieve it this way to improve my fundamental understanding of the language.
Thanks for reading!
That's because you are allocating a new instance of LocationManager. You can either connect the two controllers between them, like declaring properties and setting them accordingly.
For example, if you instantiate controller B from controller A, you should implement a property for controller B, like firstController, so :
B *controller = [[B alloc] init];
controller.firstController = A;
and then from inside B controller, you control what happens in controller A
An alternate way is to instantiate and control everything from the ApplicationDelegate. It's a more powerful pattern.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
I'm using the same convention for instance variable and properties naming as shown by sebnow in his following answer:
instance variable/ method argument naming in Objective C
I copy paste his example code here:
#interface Foo : NSObject {
id _bar;
}
#property (nonatomic, retain) id bar;
- (id) initWithBar:(id)aBar;
#end
#implementation Foo
#synthesize bar = _bar;
- (id) initWithBar:(id)aBar {
self = [super init];
if(self != nil) {
_bar = aBar;
}
return self;
}
#end
In the implementation of some methods of the Foo class, I use for example:
_bar = aBar
instead of using:
bar = aBar
The 'Analyse' tool introduced by Xcode 4 gives me this warning (I'm using version 4.0.2):
Instance variable 'bar' in class 'Foo' is never used by the methods in its #implementation (although it may be used by category methods)
Perhaps I should use:
self.bar = aBar
But for the readonly properties, that can't work, and beside that, I'm not sure if using the setter in the class itself is a good practice or not.
I'm not fresh in Objective-C, but I'm still in the beginning of learning. Perhaps I'm doing something wrong, and have a bad coding practice somewhere.
Thanks you in advance if you can help me ;)
"Is never used" should be taken literally: you only define its value in assignments, never use it.
This is the same kind of warning you get for local variables: if you only define their values and never use it, what are they for?
The static analyzer is thus warning you, because typically variables that are never accessed are just remains of older code that has changed and you can remove them. But in your case it could be perfectly fine.
The #synthesize line affects how the setter and getter for the property 'bar' operate. The line:
#synthesize bar = _bar;
Effectively says "put in the standard getter (and setter, if relevant) for bar, as per the way I've declared it as a #property, but use the instance variable _bar for the storage".
When you use self.bar as an lvalue you're actually making a method call to [self setBar:] and when you use it as an rvalue you're actually making a call to [self bar]. It looks like a normal C-style struct member access but internally it's a method call.
So, the #synthesize creates a suitable getter and setter to use for self.bar, but doesn't change the name of the instance variable. You should therefore be right to use _bar when accessing the thing directly from within the class itself (though some people now frown upon that from a style point of view) and self.bar otherwise, without receiving any analyser warnings.
For you to end up with an instance variable called bar, assuming you didn't declare one inside your interface, the most likely mistake is an error in the way you've performed your #synthesize. In the modern runtime you can supply a #property/#synthesize pair for a variable you haven't actually declared in your interface and the variable will be magically added to your interface. So you can do that by accident if you make an unfortunate typo.
If possible, could you post your actual code?
Please see my comment.
Try adding a -dealloc method to release the object. This will 'access' the Ivar and should make the static analyser happy.
-(void)dealloc
{
[bar release]; bar = nil;
[super dealloc]
}
Now that I can respond to my question 8 hours later, I'm doing it for anyone who made the same mistake as me during some test or something. However, the answers of sergio and Tommy are very informative.
After reading answers, I saw that I made a silly mistake. During a test of coding of my class, I removed the underscore before my instance variables declaration. So my actual code was truely looking like this:
#interface Foo : NSObject {
id bar;
}
#property (nonatomic, retain) id bar;
- (id) initWithBar:(id)aBar;
#end
#implementation Foo
#synthesize bar = _bar;
- (id) initWithBar:(id)aBar {
self = [super init];
if(self != nil) {
_bar = aBar;
}
return self;
}
#end
So the Analyse warnings were correct. Sorry for the false alarm! But thanks for very fast answers.
use this ->
#interface Foo : NSObject {
id _bar;
}
#property (nonatomic, retain) id _bar;
- (id) initWithBar:(id)aBar;
#end
#implementation Foo
#synthesize bar = _bar;
- (id) initWithBar:(id)aBar {
self = [super init];
if(self != nil) {
bar = aBar;
}
return self;
}
#end