How come synthesizing with an underscore is not working? - objective-c

I am trying to synthesize variables in my iPhone app with
#synthesize samples=_samples;
with samples declared as
#property (strong, nonatomic) NSMutableArray *samples;
However, I get a build error claiming that _samples does not exist. Why?

Are you trying to access the _samples from outside the implementation file? ivars generated through #synthesize are not viewable by anything outside of the implementation where the #synthesize was called. So if you do something like this...
MyView *myView = [[MyView alloc] init];
myView._sample;
...you will see an error. See here for more details: https://stackoverflow.com/a/8511046/251012
.
.
.
.
EDIT: All of the below is wrong. Left, so that the comments make sense
Are you declaring your ivar's and are the names spelled correctly?
When you say something like...
#synthesize foo = _foobar;
...you need to make sure that you set the instance variable in your interface like so...
#interface MyObject : NSObject
{
NSString *_foobar;
}
#property(nonatomic,strong) NSString *foo;
#end
To be clear, when you say foo=_foobar, foo is the base name to auto-generate the getter/setter's, and _foobar is the name of the ivar. If no ivar is declared, #property will auto-generate one of the same name.

Same code is working on my side. Try to restart xcode and rebuild the project.

Related

How to use #property correctly (Setters) within another class

another question i'm trying to use a setter within another class but I seem to get this odd error here is the code below:
AppDataSorting.h
#import <Foundation/Foundation.h>
#interface AppDataSorting : NSObject{
NSString *createNewFood;
NSNumber *createNewFoodCarbCount;
}
#property (readwrite) NSString *createNewFood;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (IBAction)saveData:(id)sender {
NSLog(#"%#", self.foodName.stringValue);
self.createNewFood = self.foodName.stringValue;
NSLog(#"%.1f", self.carbAmount.floatValue);
}
#end
I get the error message in AppDelegate.m which is: Property 'createNewFood' not found on object of type 'AppDelegate *'
Could someone please explain the issue here?
You declare this property:
#property (readwrite) NSString *createNewFood;
In AppDataSorting.h so you can access it like self.createNewFood in AppDataSorting.m file not AppDelegate.m. If you want to call it as you do in AppDelegate.m you have move this line:
#property (readwrite) NSString *createNewFood;
to AppDelegate.h file.
Or if you want to use property from AppDataSorting class in AppDelegate you have to create object and call it on that object:
- (IBAction)saveData:(id)sender {
NSLog(#"%#", self.foodName.stringValue);
AppDataSorting *dSorting = [[AppDataSorting alloc] init];
dSorting.createNewFood = self.foodName.stringValue;
NSLog(#"%.1f", self.carbAmount.floatValue);
}
In -saveData:, self refers to an instance of NSAppDelegate. The createNewFood property is defined on instances of the class AppDataSorting.
Also note that Cocoa/CF naming conventions give special meaning to methods that start with "init", "new" and (to a lesser degree) "create". You probably want to avoid such things in your property names. Details here.
In general, properties should represent conceptual "properties" of an object. So if you had a Person class, it might have a name property, but it wouldn't have a createNewOutfit property.
You need to access createNewFood on an instance of AppDataSorting - but you're trying to access the property on the AppDelegate-class which clearly doesn't implement it.
So you would need to create an instance of AppDataSorting and then access the property like so:
AppDataSorting *instance = [[AppDataSorting alloc] init];
instance.createNewFood = self.foodName.stringValue;
Final notes:
The docs provide a good base of information
If you don't need atomicity you should always declare properties with the nonatomic attribute
createNewFood is not a good name for a property since it suggests a method which creates new food - yet it's only meant to store data (in this case an NSString instance)

Overriding a readonly property in subclass

There is a class that looks like this (I'm omitting the imports for brevity):
Base.h:
#interface Base : NSObject
#property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
#end
Base.m:
#implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
#end
As you see, the 'something' property is readonly. Now I want to create a subclass that overrides that property to be writable as well:
Sub.h:
#interface Sub : Base
#property (strong) NSString *something;
#end
Sub.m:
#implementation Sub
#end
And the code:
main.c:
int main(int argc, const char * argv[]) {
#autoreleasepool {
Sub *o = [Sub new];
o.something = #"foo";
NSLog(#"%#", o.something);
}
return 0;
}
This code results in:
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
Why is that? Why doesn't it find the setSelector?
When I do this in the subclass instead:
Sub.m:
#implementation Sub
#synthesize something = _something;
#end
it all works. Does this mean the subclass' property is not synthesized by default even though it is defined as #property in the #interface? Does the compile somehow 'see' the automatically generated getter from Base and doesn't generate the setter? And why, I think the setter should be generated as it doesn't exist yet. I'm using Xcode 4.6.2 and the project is a Cli Tool (type Foundation), but the same happens in my actual project which is an iPhone app.
Background: I have a heavy object (instance of Base) that requires a Bluetooth connection to some equipment and I am supposed to create a view controller for some functionality. For easy testing I don't want to be connected to BT (actually, I would need a physical device and test the code on it), I would like to be able to test it in the simulator.
What I came up with is that I simply create a subclass (Sub) that stubs a few methods / properties and use it instead, and when the code is ready I just remove the code for the subclass, replace its instance with the correct one, test in with a device, commit and push. It actually works fine, except for the weird thing with #property above.
Could somebody tell me what is going on with property overriding?
For a readonly property, only a getter method is synthesized, but no setter method.
And when compiling the subclass, the compiler does not know how the property is realized
in the base class (it could be a custom getter instead of a backing instance variable).
So it cannot just create a setter method in the subclass.
If you want to have write access to the same instance variable from the subclass,
you have to declare it as #protected in the base class
(so that it is accessible in the subclass), re-declare the property
as read-write in the subclass, and provide a setter method:
Base.h:
#interface Base : NSObject {
#protected
NSString *_something;
}
#property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
#end
Sub.h:
#interface Sub : Base
#property (strong, readwrite) NSString *something;
#end
Sub.m:
#implementation Sub
-(void)setSomething:(NSString *)something
{
_something = something;
}
#end
Your solution
#synthesize something = _something;
generates getter and setter method in the subclass, using a separate instance
variable _something in the subclass (which is different
from _something in the base class).
This works as well, you just should be aware that self.something refers to
different instance variables in the base class and in the subclass. To make that
more obvious, you could use a different instance variable in the subclass:
#synthesize something = _somethingElse;
The given answer works perfectly fine. This is an alternative answer, that apparently Apple likes a bit more.
You can define a private extension of your class, a Base+Protected.h file, which needs to be included in Base.m and Sub.m.
Then, in this new file, you redefine the property as readwrite.
#interface Base ()
#property (strong, readwrite) NSString *something;
#end
This alternative allows you to use the accessor self.something rathern than the ivar _something.
Note: you still need to keep the definition of something in your Base.h as is.
I guess that the backing variables are the same when the property is not synthesized in the subclass. So at runtime the programm tries to call the setSomething in the superclass. But since it doesnt exist there an Exception is thrown.

.h instance variable declaration

I'm having a hard time understanding why the following textfield is declared twice in some tutorials.
In the .h file:
# include <UIKit/UIKit.h>
#interface MyViewController : UIViewController {
UITextField *name; // <----- What do I need this for? Is it the same as below?
}
#property (nonatomic, strong) IBOutlet UITextField *name; // <----- Same as this?
#end
At first I thought this would be something like an instance variable, but they are only declared here in the .m file, right?
.m file
#import "MyViewController.h"
#implementation UIViewController {
NSString *myString; // <----- This is an instance variable, right?
}
What's the "UITextField *name;" for? Don't I only need the second one with the #property in front? Thank you.
This is an old way, just use property is OK.
If you declare both, you must use #synthesize name; in your .m file to make self.name same as name.
XCode4.2 auto synthesize name = _name. So use self.name as much as possible in your .m file.
Variable in {} just use for internal or private, when you don't want implement setter and getter.
If you are targeting iPhone OS or 64-bit Mac OS X then you do not need to define ivars for your properties. Take a look at Dynamic ivars: solving a fragile base class problem

Basic Objective C defining and synthesizing properties

I have been working with Objective C for a few months now and feel like I maybe know 1% of it, and understand even less than that...
Regardless, I have two moderately popular games out, and learning more every day.
When I first started, I learned that the method of defining properties was to use the same identifier for the property and the instance variable, as follow:
code.h:
#interface MyClass : UISomething {
NSString *myPropName;
}
#property (nonatomic, retain) NSString *myPropName;
#end
code.m
#synthesize myPropName;
Recently I saw the following used, where the instance variable is named differently than the property, and then the property is set to the instance variable in the implementation:
code.h:
#interface MyClass : UISomething {
NSString *_myPropName;
}
#property (nonatomic, retain) NSString *myPropName;
#end
code.m:
#synthesize myPropName = _myPropName;
Is there a reason for not using same identifier for the property and instance variable?
Thanks!
Hanaan
Is there a reason for not using same
identifier for the property and
instance variable?
Not really. Some people like the convention of prefixing the instance variables with an underscore. (Seems pointless to me.) Other people like to change the property names for boolean variables:
#synthesize isEmpty = empty;
You might also want to use a shorter identifier for the instance variable and more descriptive name for the property (audioPlayer = player). And one final application comes to mind, renaming variables in combination with protocols:
#interface LowLevelAudioPlayer : NSObject <AudioLevelProvider> {…}
#interface Jukebox : NSObject {
LowLevelAudioPlayer *player;
}
#property(readonly) id <AudioLevelProvider> levelMeter;
#synthesize levelMeter = player;
Here it’s beneficial to rename the variable as you are only providing access to one of its facets.

variable accessing

I have a variable x in one class.And I want to access the updated x value in some other class.
There is so much of confusion.Can I use property?.Please help me.
Thanks in advance
Do you mean that you want to be told when the value changes? Have a look at Key Value Observing
To simply access an iVar in one class from another, a property is exactly what you want.
The syntax is :
in your .h
#interface myclass : NSObject {
UIWindow *window;
}
#property (nonatomic, retain) UIWindow *window;
#end
in your .m
#implementation myclass
#synthesize window;
...
#end
The #synthesize directive instructs the compiler to produce a lot of boilerplate code (as directed by the (nonatomic, retain) specifiers. In this case to handle thread safety and memory management.
Also note that in Objective-C 2.0 the iVar declaration UIWindow *window; is not required.
If you want to be notified in your second class when an iVar is updated, you need to look at key value observing. Unless you are writing a framework or some very dynamic code, that is probably overkill.
Maybe this tutorial will help you out..
If this is not what you mean, please rephrase the question, because i don't understand it..
Edit: Or a shared Instance can be used
you could access it by #import Classname, and then just use the getter that is created with the property. but first initialize the class you have imported..
#import "ClassY.h"
#implementation ClassX
ClassY * classY;
NSString * name;
...
name = [classY name];
...
#end