I understand that starting with iOS 4, there is now the ability to not declare iVars at all, and allow the compiler to automatically create them for you when you synthesize the property. However, I cannot find any documentation from Apple on this feature.
Also, is there any documentation on best practices or Apple recommended guidelines on using iVars and properties? I have always use properties like this:
.h file
#interface myClass {
NSIndexPath *_indexPath
}
#property(nonatomic, retain) NSIndexPath *indexPath
#end
.m file
#implementation myClass
#synthesize indexPath = _indexPath;
- (void)dealloc {
[_indexPath release];
}
#end
I use the _indexPath instead of indexPath as my iVar name to make sure that I don't ever use indexPath when I need to use self.indexPath. But now that iOS supports automatic properties, I don't need to worry about that. However, if I leave out the iVar declaration, how should I handle releasing it in my dealloc? I was taught to use iVars directly when releasing in dealloc, rather than using the property methods. If I don't have an iVar at design-time, can I just call the property method instead?
I've went through many different ways of dealing with this. My current method is to use the property access in dealloc. The reasons not to are too contrived (in my mind) to not do it, except in cases where I know the property has odd behavior.
#interface Class
#property (nonatomic, retain) id prop;
#end
#implementation Class
#synthesize prop;
- (void)dealloc;
{
self.prop = nil;
//[prop release], prop=nil; works as well, even without doing an explicit iVar
[super dealloc];
}
#end
In constrast, I do the following:
#interface SomeViewController : UIViewController
#property (nonatomic, copy) NSString *someString;
#end
and then
#implementation SomeViewController
#synthesize someString;
- (void)dealloc
{
[someString release], someString = nil;
self.someString = nil; // Needed?
[super dealloc];
}
#end
Note: At some point Apple will enable synthesize-by-default which will no longer require the #synthesize directive.
You can directly access instance variables using -> symbol instead of dot . (which will invoke ivar's corresponding accessor method):
.h
#interface myClass {
}
#property(nonatomic, retain) NSIndexPath *indexPath
#end
.m
#implementation myClass
- (void)dealloc {
[self->indexPath release];
self->indexPath = nil; // optional, if you need it
[super dealloc];
}
#end
Thus you will directly access iVar and not it's corresponding accessor method, obtaining additional benefit - performance.
Related
I am learning Objective-C and I am trying to split the class definition from the implementation as shown below.
Now in the code I want to reference the both of:
NSString *CarMotorCode;
NSString *CarChassisCode;
In the implementation file. I attempted to use:
self.CarMotorCode;
self.CarChassisCode;
But it does not work. Would you please let me know how to reference it.
Note: please let me know what is the right naming convention for the variables enclosed inside the brackets in the implementation section? Are they member variables?
Car2.m:
#import <Foundation/Foundation.h>
#import "Car2.h"
#implementation Car2
-(id) initWithMotorValue:(NSString *)motorCode andChassingValue:(NSInteger)ChassisCode {
self
}
#end
Car2.h
#ifndef Car2_h
#define Car2_h
#interface Car2 : NSObject {
NSString *CarMotorCode;
NSString *CarChassisCode;
}
-(id) initWithMotorValue: (NSString *) motorCode andChassingValue: (NSInteger) ChassisCode;
-(void) startCar;
-(void) stopCrar;
#end
#endif /* Car2_h */
You have declared instance variables (ivars). To get the “dot syntax”, you need to declare properties. The “dot syntax” is syntactic sugar that makes use of the “accessor methods” that are synthesized for you when you declare a property. (FWIW, it’s advised to not declare ivars manually, anyway, and rather to declare properties and let the compiler synthesize the necessary ivars. See Programming with Objective-C: Properties Control Access to an Object’s Values and Practical Memory Management: Use Accessor Methods to Make Memory Management Easier.)
Thus:
#interface Car2: NSObject
#property (nonatomic, copy) NSString *motorCode;
#property (nonatomic, copy) NSString *chassisCode;
- (id)initWithMotorCode:(NSString *)motorCode chassisCode:(NSString *)chassisCode;
#end
And your init method might look like:
#implementation Car2
- (id)initWithMotorCode:(NSString *)motorCode chassisCode:(NSString *)chassisCode {
if ((self = [super init])) {
_motorCode = [motorCode copy];
_chassisCode = [chassisCode copy];
}
return self;
}
#end
That will synthesize ivars _motorCode and _chassisCode for you behind the scenes, but you generally wouldn’t interact directly with them (except in init method, in which case you should avoid accessing properties). But in the rest of your instance methods, you could just use the properties self.motorCode and self.chassisCode.
A few unrelated notes:
I dropped the car prefix in your property names. It seems redundant to include that prefix when dealing with a car object.
I start my property names with lowercase letter as a matter of convention.
I changed the init method signature to better mirror the property names (e.g. not initWithMotorValue but rather initWithMotorCode).
Alternatively, you might use the strong memory qualifier rather than copy. E.g.
#interface Car2: NSObject
#property (nonatomic, strong) NSString *motorCode;
#property (nonatomic, strong) NSString *chassisCode;
- (id)initWithMotorCode:(NSString *)motorCode chassisCode:(NSString *)chassisCode;
#end
And
- (id)initWithMotorCode:(NSString *)motorCode chassisCode:(NSString *)chassisCode {
if ((self = [super init])) {
_motorCode = motorCode;
_chassisCode = chassisCode;
}
return self;
}
But we often use copy to protect us against someone passing a NSMutableString as one of these properties and then mutating it behind our back. But this is up to you.
You defined chassisCode to be a string in your ivar declaration, but as an NSInteger in your init method signature. Obviously, if it’s an NSInteger, change both accordingly:
#interface Car2: NSObject
#property (nonatomic, copy) NSString *motorCode;
#property (nonatomic) NSInteger chassisCode;
- (id) initWithMotorCode:(NSString *)motorCode chassisCode:(NSInteger)chassisCode;
#end
and
- (id)initWithMotorCode:(NSString *)motorCode chassisCode:(NSInteger)chassisCode {
if ((self = [super init])) {
_motorCode = [motorCode copy];
_chassisCode = chassisCode;
}
return self;
}
If you’re wondering why I didn’t use the property accessor methods in the init method, please see Practical Memory Management: Don’t Use Accessor Methods in Initializer Methods and dealloc.
I'm following one of the iOS tutorials from Ray Wenderlich (Scarybugs part 1). But I notice for each property in the model, he always "#synthesize" it in the implementation.
Here is the example of the models:
#import <Foundation/Foundation.h>
#interface RWTScaryBugData : NSObject
#property (strong) NSString *title;
#property (assign) float rating;
- (id)initWithTitle:(NSString*)title rating:(float)rating;
#end
--
#import "RWTScaryBugData.h"
#implementation RWTScaryBugData
#synthesize title = _title;
#synthesize rating = _rating;
- (id)initWithTitle:(NSString*)title rating:(float)rating {
if ((self = [super init])) {
self.title = title;
self.rating = rating;
}
return self;
}
#end
--
#import <Foundation/Foundation.h>
#class RWTScaryBugData;
#interface RWTScaryBugDoc : NSObject
#property (strong) RWTScaryBugData *data;
#property (strong) UIImage *thumbImage;
#property (strong) UIImage *fullImage;
- (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(UIImage *)thumbImage fullImage:(UIImage *)fullImage;
#end
--
#import "RWTScaryBugDoc.h"
#import "RWTScaryBugData.h"
#implementation RWTScaryBugDoc
#synthesize data = _data;
#synthesize thumbImage = _thumbImage;
#synthesize fullImage = _fullImage;
- (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(UIImage *)thumbImage fullImage:(UIImage *)fullImage {
if ((self = [super init])) {
self.data = [[RWTScaryBugData alloc] initWithTitle:title rating:rating];
self.thumbImage = thumbImage;
self.fullImage = fullImage;
}
return self;
}
#end
I know "#synthesize" is basically to allocate an instance variable for a property, but it has been taken care of by default for every "#property" in ".h file" (although not visible).
My questions is: is it necessary to "#synthesize" every "#property" we have in our public API? (I tried deleting all the "#synthesize" in the implementation, and it still worked)
#synthesize is no longer needed. The compiler will synthesize the getter and setter as required with an instance variable named as _<propertyName> automatically. It creates the instance variable but more importantly it creates the getter and setter methods (for readwrite properties).
If you've manually provided the getter/setter for a property, then an instance variable won't be automatically synthesized, and you'll need to add the #synthesize statement. From the docs:
Note: The compiler will automatically synthesize an instance variable in all situations where it’s also synthesizing at least one accessor method. If you implement both a getter and a setter for a readwrite property, or a getter for a readonly property, the compiler will assume that you are taking control over the property implementation and won’t synthesize an instance variable automatically.
If you still need an instance variable, you’ll need to request that one be synthesized:
#synthesize property = _property;
As noted in the Objective-C Feature Availability Index, automatic synthesis of property instance variables was introduced with Xcode 4.4 (LLVM Compiler 4.0) and requires the modern runtime (all code on iOS, 64-bit code on OS X).
So, the tutorial is a bit dated, that's all.
hope this will help little more.
#property(nonatomic) NSString *name;
the #property is an Objective-C directive which declares the property
-> The "`nonatomic`" in the parenthesis specifies that the property is non-atomic in nature.
-> and then we define the type and name of our property.
-> prototyping of getter and setter method
now go to .m file
previously we have synthesis this property by using #synthesis , now it also NOT required , it automatically done by IDE.
-> this #synthesis now generate the getter and setter(if not readonly) methods.
and Then why we even write #synthesis in our code if it always done by IDE .
one of the basic use is :-
what our IDE do internally
#synthesis name=_name;
we use _name to access particular property but now you want synthesis by some other way like
firstname you can do it like
#synthesis name= firstname
or just by name
#synthesis name=name
So from it you can access this property as you want.
I am trying to create non-atomic copy accessors, and I read everywhere that the object should be released at the end. So, if you could help me understand whether I am doing it properly, I would appreciate it. Will the following be correct?
#interface ClassA: NSObject
{
NSString* stringA;
}
#property (nonatomic, copy) NSString* stringA;
#implementation ClassA
#synthesize stringA;
-(void) setStringA: (NSString*) stringInput {
if(stringA != stringInput) {
[stringA release];
stringA = [stringInput copy];
}
}
-(void) dealloc {
[stringA release];
[super dealloc];
}
I am looking for a confirmation whether I need to deallocate stringA in the dealloc method at the end and whether I did it correctly.
Many thanks.
You need to release it, yes. (You don't deallocate things. You release your ownership of them and they may be deallocated as a result.)
Your code is correct.
The rules are that you must release any object you receive from a method whose name begins with "alloc" or "new" or contains "copy". You also must release any object that you retain. Since you call -copy on stringInput, you are responsible for eventually releasing the object you receive from that.
#Ken Thomases is right; your code is correct. A few things, though:
You don't really need to declare the ivar, or synthesize the property, or write your own setter; all this is done for you. So your code (while correct) could be simplified to:
#interface ClassA: NSObject
#property (nonatomic, copy) NSString* stringA;
#end
#implementation ClassA
-(void) dealloc {
[_stringA release];
[super dealloc];
}
#end
Second, if you're using ARC (which I recommend), the code can be simplified even further (by removing the dealloc override completely).
#interface ClassA: NSObject
#property (nonatomic, copy) NSString* stringA;
#end
#implementation ClassA
#end
In this case stringA is released by your class on dealloc, but you don't have to write code to do that; ARC does it for you.
I am interested in setting a property as a subclass, say Person, of NSManagedObject in a view controller that will specify an instance of person so that I will be able to update with methods in the controller. can I do it like this?
// Viewcontroller.h
#implementation
#property (nonatomic, retain) Person* currentPerson;
#end
// ViewController.m
#implementation
#dynamic currentPerson;
-(void) doSomethingToCurrentPerson {
currentPerson.SomeAtrribute=somevalue;
}
#end
It seems like if this were not a valid way to go, it would also be possible to set a unique identifier and then store CurrentPersonUniqueID as a property and use KVC. Is there a way to get something along the lines of what I posted to work, or am I better off with something closer to the KVC approach, or something totally different?
This code won't work until you replace #dynamic by #synthesize. #dynamic tells the compiler that -setCurrentPerson: and -currentPerson are implemented somewhere else, which is not the case.
So #synthesize currentPerson will create the currentPerson's getter/setter automatically. It won't have anything to do with the fact that Person is a NSManagedObject.
Also, either you can't access to currentPerson directly with this name, you have to use its getter:
self.currentPerson.attribute = something;
// or
[self currentPerson].attribute = something;
Correct code:
// Viewcontroller.h
#implementation
#property (nonatomic, retain) Person* currentPerson;
#end
// ViewController.m
#implementation
#synthesize currentPerson;
-(void) doSomethingToCurrentPerson {
self.currentPerson.SomeAtrribute = somevalue;
}
#end
I am starting my first Cocoa Project. And I have a serious (for me) but maybe easy problem (for you) to solve and I need some direction where to start.
The short description: I have built a class "PortConnection.h" who writes all ports found by an external class (AMSerial.h) into an array when the function -listPorts is called. Here is the code for the PortConnection.h
#import <Cocoa/Cocoa.h>
#import "AMSerialPortList.h"
#import "AMSerialPortAdditions.h"
#import "AMSerialPort.h"
#interface PortConnection : NSObject {
#private
AMSerialPort *port;
NSMutableArray *portArray;
}
- (void)listDevices;
#property (nonatomic, retain) NSMutableArray *portArray;
#property (nonatomic, retain) AMSerialPort *port;
#end
and following the PortConnection.m
#import "PortConnection.h"
#import "AMSerialPortList.h"
#import "AMSerialPortAdditions.h"
#import "AMSerialPort.h"
#implementation PortConnection
#synthesize portArray;
#synthesize port;
- (void)listDevices
{
// get an port enumerator
NSEnumerator *enumerator = [AMSerialPortList portEnumerator];
AMSerialPort *aPort;
while ((aPort = [enumerator nextObject]))
{
// Add Devices to Array
[portArray addObject:[aPort bsdPath]];
}
}
So far it is perfectly working.
Now my questions
I have implemented an tableView in the GUI for display the results of the method called above. This file is called "PortTableViewController.h" and is the datasource for my TableView.
Here is the .h file
#import <Foundation/Foundation.h>
#import "PortConnection.h"
#interface PortTableViewController : NSObject <NSTableViewDataSource> {
#private
IBOutlet NSTableView *portTableView;
}
#property (assign) IBOutlet NSTableView *portTableView;
#end
and here is the .m file:
#import "PortTableViewController.h"
#import "PortConnection.h"
#implementation PortTableViewController
#synthesize portTableView;
#pragma mark -
#pragma mark TableView Delegates
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
PortConnection *portConnection = [[PortConnection alloc] init];
[portConnection listDevices];
return [portConnection.portArray count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
??????? I DO NOT HAVE A CLUE HOW TO ACCESS THE ARRAY IN PORTCONNECTION.M CORRECTLY
}
#end
QUESTIONS:
1) When having a look on the TableViewDataSourceDelegates how do I access the filled portArray in the PortConnection.m class correctly. It doesn't seem to work the way I do it.
2) Do I have to create an Object from Portconnection.h every time I want to retrieve Data from it in a tableviewdelegate method?
I am really thankful for every kind of help! I want to learn something.. and I really appreciate your support! Thanks.. for question in order to help me, don't hesitate. I really appreciate it....
Thanks
Sebastian
A simple fix is to have your table view controller declare an instance variable that holds a PortConnection instance. This instance is created and sent -listDevices in -init, it is used by all methods in your table view controller (which means that all methods refer to the same PortConnection instance), and released in -dealloc.
For example:
PortTableViewController.h
#import <Foundation/Foundation.h>
#import "PortConnection.h"
#interface PortTableViewController : NSObject <NSTableViewDataSource> {
#private
IBOutlet NSTableView *portTableView;
PortConnection *portConnection;
}
#property (assign) IBOutlet NSTableView *portTableView;
#end
PortTableViewController.m
#import "PortTableViewController.h"
#import "PortConnection.h"
#implementation PortTableViewController
#synthesize portTableView;
#pragma mark -
#pragma mark TableView Delegates
- (id)init {
self = [super init];
if (self) {
portConnection = [[PortConnection alloc] init];
[portConnection listDevices];
}
return self;
}
- (void)dealloc {
[portConnection release];
[super dealloc];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return [portConnection.portArray count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
return [portConnection.portArray objectAtIndex:row];
// or whatever behaviour provides an object value for the column/row
}
#end
If you don't want to create a field in every delegate you could create a static variable in PortConnection which holds the array. Initially the array is nil and on the first call to get the ports you create the list if needed.
In the implementation file:
static NSMutableArray *portArray;
+ (NSArray) listPorts {
if(portArray != nil)
return (NSArray *)portArray;
NSEnumerator *enumerator = [AMSerialPortList portEnumerator];
AMSerialPort *aPort;
portArray = [[NSMutableArray alloc] init];
while ((aPort = [enumerator nextObject])) {
// Add Devices to Array
[portArray addObject:[aPort bsdPath]];
}
}
This of course depends on how often the portArray will change, if it's often I would probably just generate it every time.
You could also do a getPortArray which calls generatePortArray if portArray is nil
You should only need a single PortConnection instance, but your table view controller will somehow need to know about it. It could be that the PortTableViewController creates and owns the PortConnection object, or it could be that some other object, like the app delegate or another controller creates it.
In the former case, it's trivial... the PortTableViewController creates the PortConnection instance, and therefore it has a reference to it and can access its portArray property at well.
In the latter case, things aren't much more complicated: the object that creates the PortController should give the PortTableViewController a pointer to the PortController. The PortTableViewController should then retain the PortController and stash the pointer in an instance variable so that it can access the portArray property as needed.