How can I grant certain classes to set my properties in Objective-C? - objective-c

Two questions:
How can I allow only certain class to update a property? I tried using category but the NotFriendly class is still able to set the age property via Key-Value.
How come I get the "-[Person setAge:]: unrecognized selector sent" error when I tried to the age property during runtime?
Thanks,
Person.h
#interface Person
#property (readonly) NSString *age;
#end
Person.m
#implementation Person
#synthesize age;
#end
Person+Exclusive.h
#interface Person
#property (readwrite) NSString *age;
#end
Person+Exclusive.h
#implementation Person (Exclusive)
#end
Friendly.m
#import "Person+Exclusive.h"
#interface Friendly
- (void)viewDidLoad {
[super viewDidLoad];
Person *aPerson = [[Person alloc] init];
aPerson.age = #"12"; // -[Person setAge:]: unrecognized selector sent to instance 0x174013e90
}
NotFriendly.m
#import "Person.h"
#interface Friendly
- (void)viewDidLoad {
[super viewDidLoad];
Person *aPerson = [[Person alloc] init];
[aPerson setValue:#"1000000" forKey:#"age"]; // how can I stop this
}

You can't reliably. Any method added to an Objective-C class is visible to everyone in the runtime; available methods are how key-value coding works.
If it's just KVC you want to block then you can override setValue:forKey: and decline to act if the names key is on your blacklist; otherwise call up to super. But classes will still be able to performSelector:withObject: or even drop down to the C runtime, the latter of which you can ultimately do nothing about.
If you are in a position where Person can be responsible for creating those objects that are permitted to talk to it then it can demand an instance as an argument to the setter and continue only if that instance is one you created. Keep a list in one of the weak collections of everything you instantiated.
In any detected failing case, by whatever means, you can manually raise an NSException to create the type of failure you desire.
If it's just for debugging builds and you don't mind a bunch of hassle, you can call [NSThread callStackSymbols] and parse the result to find out which type of class is calling. The text returned has no formally defined format though it's been fairly stable until now; it's explicitly not reliable for release builds. But it shouldn't be too much work to keep it working within debug builds as a diagnostic tool.

Not sure why you would want to do this, but it is an interesting question.
I wonder if you could create a method in person that takes two arguments, age and class. Then when you call it, you use [self class] to pass in the class. Something like this:
- (void)checkTheClassBeforeSettingAge:(NSString *)age withClass:(NSClass *)class {
if (class isKindOfClass:[validClass class]) then {
self.age = age;
} else {
// Error handling code
}
}
Call it with:
checkTheClassBeforeSettingAge:#"12" withClass:[self class];

Related

Objective-C class as NSMutableArray

Very simple question. Is it possible to create a class which is a list by it self? I mean:
I do
taskList *taskList1 = [[taskList alloc] init];
And than simply:
taskList1 addObject:[task1]
May seem stupid, but I'm totally new to O-C syntax
I'd need two methods:
-(instancetype) init;
which just initialize as an empty list
+(instancetype)taskList;
to allocate taskList instance
and last thing:
In interface i use:
#interface taskList : NSObject
or
#interface taskList : NSMuttableArray
I got stuck on something specific, didn't I? I'm sorry that I bother you with my programming level.
Alright, I gave up, just last question, because I have to finish it very soon.
I changed my approach I added
#property NSMutableArray *list;
Why does this:
taskList *TL1 =[taskList initTaskList];
task *task1 = [[task alloc] init];
task *task2 = [[task alloc] init];
TL1.list addObject:[task1];
doesn't work, I have "Expected identifier" Error
If you read the subclassing notes on NSArray / NSMutableArray you'll see that Apple recommend against subclassing them because they are a class cluster. (i.e. what you really get when you ask for one is an undocumented subclass, and the initialiser decides which undocumented subclass to return to you based on some undocumented qualifiers..
So just make an NSObject subclass which owns a (private) strong property of type NSMutableArray, and publish an api to access that array..
eg
#import "modelList.h"
//dont worry header is empty, its up to you to do that.. this is a subclass on NSObject
#interface modelList()
#property (strong, nonatomic) NSMutableArray *backingArray;
#end
#implementation modelList
#synthesize backingArray = _backingArray;
-(instancetype )init{
if (self = [super init]) {
[self setBackingArray:[[NSMutableArray alloc]init]];
}
return self;
}
//public API (the stuff that is prototyped in the header..)
-(id)objectAtIndex:(NSUInteger )index{
return [self.backingArray objectAtIndex:index];
}
-(BOOL )containsObject:(id)object{
return [self.backingArray containsObject:object];
}
-(void )addObject:(id)object{
//example application, qualifying object..
if ([object conformsToProtocol:#protocol(NSCoding)]) {
[self.backingArray addObject:object];
}
}
-(NSUInteger )count{
return [self.backingArray count];
}
//etc etc declare publicly the things you need to get the job done
#end
so far this is just a face for a mutable array obviously, but it gives you a place for whatever other model logic you need. good luck

Which one is initialized, property or its instance variable

Suppose I have a property called myPropertyName defined in my class MyClassName. Manual memory management is used throughout this post.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
#private
NSObject* myPropertyName;
#public
}
#property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
#synthesize myPropertyName;
// Some methods are here
#end
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
This one is calling myPropertyName setter, but I'm not sure what is the name of the instance variable being used in the setter, myPropertyName (since I've declared a #private field named myPropertyName) or _myPropertyName (people say that this one with underbar is the default)?
myPropertyName = [[NSObject alloc] init];
Does this initialize the instance variable of the myPropertyName property? If I don't have #synthesize myPropertyName = _myPropertyName;, would it be wrong since the default instance variable for the property is said to be _myPropertyName.
_myPropertyName = [[NSObject alloc] init];
Is _myPropertyName still declared as the instance variable for my property myPropertyName even if I use #synthesize myPropertyName; and #private NSObject* myPropertyName;?
In my understanding, a property is just a name (such as myPropertyName), there should be some instance variable encapsulated to be used in actual operations in the code, such as assigning values.
First off, I highly recommend reading Apple's documentation on properties, also linked by nhgrif. However, I understand docs can be a bit dense reading material (though Apple's, I find, are not so bad), so I'll give a brief overview of properties here.
I like examples, so I'm going to rewrite your two classes in a bit more current form.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject
#property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
// some methods here
#end
The class MyClassName now has a property called myPropertyName of type NSObject *. The compiler will do a lot of work for you for "free" in this instance. Specifically, it will generate a backing variable, and also generate a setter and getter for myPropertyName. If I were to rewrite the two files, and pretend I'm the compiler, including that stuff, they would look like this:
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
NSObject *_myPropertyName;
}
#property (nonatomic, strong) NSObject *myPropertyName;
- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
- (void)setMyPropertyName:(NSObject *)obj
{
_myPropertyName = obj;
}
- (NSObject *)myPropertyName
{
return _myPropertyName;
}
#end
Again, all of this is happening for "free": I'm just showing you what's happening under the hood. Now for your numbered questions.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
First of all, you should probably be using Automatic Reference Counting, or ARC. If you are, you won't be allowed to call autorelease. Ignoring that part, this works fine. Excluding the autorelease, this is exactly equivalent to:
[self setMyPropertyName:[[NSObject alloc] init]];
Which, if you look at the second .m file I wrote out, above, will basically translate to:
`_myPropertyName = [[NSObject alloc] init];
myPropertyName = [[NSObject alloc] init];
As written, this code will give a compiler error, since there is no variable called myPropertyName in this class. If you really want to access the instance variable underlying (or, "backing") the myPropertyName property, you can, by using its real name:
_myPropertyName = [[NSObject alloc] init]; // note the underscore
But most of the time, it's better to use the setter, as in point 1., since that allows for side effects, and for Key-Value Coding, and other good stuff.
_myPropertyName = [[NSObject alloc] init];
Oh. Well you got it. See point 2.
You mentioned that:
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
In case it hasn't been made clear, a property is something of an abstract concept; its data is stored in a normal instance variable, typically assigned by the compiler. Its access should usually be restricted to the setter and getter, with important exceptions. To keep this answer short, I won't go into more detail than that.
One more thing: as nhgrif mentioned, you don't need to use the #synthesize keyword anymore. That is implicitly understood by the compiler now.
If you're not sure about any of this, post a comment or, better yet, read the docs.
Let's take this example:
#property NSString *fullName;
If in the implementation, we override the setters and getters, and in these setters and getters, we don't use an instance variable fullName, it is never created. For example:
- (NSString *)fullName
{
return [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
}
- (void)setFullName:(NSString *)fullName
{
//logic to split fullName into two strings
//self.firstName = etc
//self.lastName = etc.
}
In this example, there is no instance variable for fullName created.
This is according to Apple's Official Documentation
If, however, you don't override both the setter and getter, an instance variable is created.
As a sidenote, you can declare a property readonly, and then simply overriding the getter (without using the variable) will prevent an ivar being created. Likewise, you can declare a property writeonly and just override the setter.

objective-c "generic" type for #property for use with multiple subclasses

i'm not sure of the most eloquent way to state this but i will give it my best. i have created a custom class that is a generic object with some properties. i have created a couple subclasses to extend that and make them more specific than the superclass. so for the sake of example i will throw out some generic example code that may or may not be proper syntax only to illustrate what i would like to accomplish.
#interface Vehicle : NSObject
#property (nonatomic) int wheels;
- (id)initWithNumberOfWheels:(int)wheels;
#end
from there i create some subclasses for same "car" & "truck" which give more detail to the class.
#interface Car : Vehicle
#property (nonatomic) BOOL convertible;
#property etc...
#end
and...
#interface Truck : Vehicle
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#end
so here is where it gets interesting. i want to create another class that allocates those objects but i want the "type" of vehicle to be determined in the init method but use the same #property variable. so for example (and again, this is all garbage code just to give a visual representation)
Road.h
#import "Car.h"
#import "Truck.h"
#interface Road : NSObject
#property (strong, nonatomic) NotSureWhatToUseHereToMakeThisWork *myRide;
// doesn't work: #property (strong, nonatomic) id myRide;
// doesn't work: #property (strong, nonatomic) Vehicle *myRide;
- (id)initWithCars;
- (id)initWithTrucks;
#end
Road.m
#implementation Road
- (id)initWithCars
{
//standard init code...
myRide = [[Car alloc] initWithNumberOfWheels:4];
myRide.convertable = NO;
}
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myRide.is4x4 = YES;
}
#end
the bottom line is if i use the superclass in the #property it doesn't get the subclass properties obviously. basically i want to keep all this as generic and reusable as possible. it doesn't make since to make a special "road" class just for cars & one for trucks. a road is a road after all. is there anyway to do what i am after? is there a better way to do something like this? the primary purpose is to have objects that inherit specific properties for specific situations only. the reason i don't want to make extra #properties is i don't want those visible if they aren't applicable to the situation.
edit:
i added a couple extra snippets to show what i tried before even posting this question that didn't work.
answer: the correct "answer" if anyone is curious is located in CRD's response in the "Addendum". the reason this works is the type "id" can only call methods and does not inherit properties. so rather the workaround (i say it that way, as i was researching this, came to the conclusion this is not good programming and should probably be avoid if possible) would be to use the accessor methods to get/set the property.
id mySomethingObject = [[SomeClass alloc] init...];
[mySomethingObject setPropertyMethod]...; //sets value
[mySomethingObject propertyMethod]...; //gets value
rather than trying to use...
mySomethingObject.property = ; //set
mySomethingObject.property; //get
as stated in the correct answer, if your class you allocated "id" to does not respond to that method your program will crash.
You appear to be confusing a number of issues.
First there is the type of an instance vs. the type of variables which hold references to instances. When an object is created is it of some specific type and that types does not change[*]. Variables also have a type, and that does not change either. Subtyping/inheritance allows you to store a reference to an object of some type, T, in a variable of some other type, S, provided S is a supertype of T.
Second there is static vs. dynamic typing. While Objective-C uses dynamic typing, where the actual type of objects used in some operation is determined at run time, the compiler itself uses static typing, where types are determined during compilation, to aid in writing correct programs. Sometimes the compilers static checking will just produce warnings, but in other cases the compiler will refuse to compile something. In particular property references are compiled based on static typing.
In your example this means you cannot directly reference a property of Car on an object referenced by a variable of type Vehicle *, even if you know the referenced object is a Car - as at compile time all that is known is that is it a Vehicle.
The solution is to first test the actual type of the referenced object and then introduce a local variable of the more precise type, or use a lot of casts. For example:
// (a) create an object of type Car (for a Reliant Robin ;-))
// (b) create a variable of type Car and store in it a reference to the created Car
Car *myCar = [[Car alloc] initWithNumberOfWheels:3];
// Create a variable of type Vehicle and store in it the reference stored in myCar
// The created instance is *still* a Car
Vehicle *myRide = myCar;
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
// create a variable of type Car to avoid having to continually cast myRide
Car *myCarRide = (Car *)myRide; // due to if above we know this cast is valid
if (myCarRide.isConvertible) ...
To do this without the intermediate variable you use a cast:
...
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
if (((Car *)myCarRide).isConvertible) ...
Which shows why the intermediate variable approach is better!
As a final example, you write your initWithTrucks method like this:
- (id)initWithTrucks
{
//standard init code...
Truck *myTruck = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myTruck.is4x4 = YES;
// Store the reference to the created Truck in myRide
myRide = myTruck;
}
HTH
Addendum
From your comments it seems you may be looking for dynamic typing and do not wish to the compiler to perform any static typing. This is (partially) supported, but not using the dot notation for properties - you must use the getter and setter methods directly.
First, in Road you declare myRide to be type id:
#interface Road : NSObject
#property id myRide;
The id type means two things (a) any object reference and (b) do not statically check a method exists on the object. However the compiler must know that a called method exists on some object, and it will still perform static type checks on the arguments to the method - so its not complete dynamic typing (however you could pass id typed expressions or declare your methods to take arguments of type id of course...).
Second you make all references to properties use the getter or setter methods directly and do not use the dot notation (for non-property methods you just call them as usual). E.g.:
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
[myRide setIs4x4:YES];
}
If you make a call such as [myRide setIs4x4:YES] and myRide is referencing a Car object then you will get a runtime error.
The general recommendation is to stick as much as possible with the compiler's static typechecking.
[*] We will ignore any runtime magic, there be dragons. In normal code objects never change type.
You have to use the type "Vehicle" and then cast your object with "Truck" or "Car" to get the specific properties
the most generic architecture would be to create a VehicleProtocol, that any class could implement. you still could have a Vehicle class that implements the protocol and subclass from it (similar to NSObject implementing the NSObject protocol), or let independent classes implement it. the road would have a property #property (strong) id<VehicleProtocol> myRide.
A complete example of the later architecture: no vehicle super class, but all a VehicleProtocol
#import <Foundation/Foundation.h>
#protocol VehicleProtocol <NSObject>
#property (nonatomic) NSUInteger wheels;
#end
#interface Car : NSObject <VehicleProtocol>
#property (nonatomic) BOOL convertible;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Car
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Truck : NSObject <VehicleProtocol>
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Truck
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Road : NSObject
#property (strong) id<VehicleProtocol> myRide;
#end
#implementation Road
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *vehicles = #[[[Car alloc] initWithNumberOfWheels:4], [[Car alloc] initWithNumberOfWheels:3], [[Truck alloc] initWithNumberOfWheels:10]] ;
for (id v in vehicles) {
if ([v isKindOfClass:[Truck class]]) {
[v setIs4x4:YES];
}
}
Road *road = [[Road alloc] init];
road.myRide = vehicles[0];
NSLog(#"%#", road.myRide);
road.myRide = vehicles[2];
NSLog(#"%#", road.myRide);
NSObject *obj = [[NSObject alloc] init];
road.myRide = obj; // warning in this line
NSLog(#"%#", road.myRide);
}
return 0;
}
Sure it might have more lines of codes than with "classical subclassing", but there are less dependencies. Instead the classes agree on a contract to fulfill. Here the contract only requires the objects to have any number of wheels.
Note that I create a Road and assign first a car and than a truck (I also show how to identify cars and trucks via -isKindOfClass:), both works without any warning or error, as Car and Truck completely fulfill the contract. Than I assign a plain NSObject. Here the compiler warns, as he recognizes that NSObject does not implement the protocol. Though it is not an compiler error, as the compiler does not know, if you will use any protocol specific method on that object.
In case of a plain NSObject assigned to myRide, this line
NSLog(#"%# %ld", road.myRide, (unsigned long)road.myRide.wheels);
will lead to a runtime crash (as an NSObject instance does not respond to wheel) — but at compile time it will not even trigger a warning.
Storing a Car in a variable of type Vehicle * does not remove the object's Car properties — the Car will still be able to access all of its state normally — it just means that you can't access the properties through that variable.
But that's the basic idea here, isn't it? You want this class to be able to handle all Vehicles, and that's what it's doing — it's only showing you the functionality available to all Vehicles. So you can have the interface necessary for interaction with a generic Vehicle in the Vehicle class, and implement the methods in your subclasses to do the class-appropriate behavior when called, and everything will work.
If the issue is specifically creating new instances of a specific class that you want to treat generically from that point on, you can use a statically typed local variable and assign to the generically typed variable once it's set up.
For example, let's say we have a game where there are human players and AI players, and the human player can give himself an advantage by making AI players take more damage. We could do this:
#interface Combatant : NSObject
#property(nonatomic, strong) NSString *name;
#property(nonatomic) int hitPoints;
- (void)takeDamage:(int)damageAmount;
#end
#implementation Combatant
- (void)takeDamage:(int)damageAmount {
self.hitPoints -= damageAmount;
}
#end
#interface HumanCombatant : Combatant
#property(nonatomic, strong) UserID *userID;
- (id)initWithUserID:(UserID *)theID;
#end
#implementation HumanCombatant
- (id)initWithUserID:(UserID *)theID {
if ((self = [super init])) {
_userID = [theID retain];
}
}
- (void)takeDamage:(int)damageAmount {
[super takeDamage: damageAmount];
NSLog(#"Human took %d damage, has %d health remaining", damageAmount, self.hitPoints);
}
#end
#interface AICombatant : Combatant
#property(nonatomic) double damageMultiplier;
#end
#implementation AICombatant
- (void)takeDamage:(int)damageAmount {
int modifiedDamage = damageAmount * self.damageMultiplier;
[super takeDamage: modifiedDamage];
NSLog("AI took %d damage, has %d health remaining", modifiedDamage, self.hitPoints);
}
#end
Then, in most of our game code, we can use a variable typed as a Combatant *, and when you send it takeDamage:, it will do the right thing for the type of combatant it is. Our external code that calls the object a Combatant * will not be able to directly access an AICombatant's damageMultiplier property, because the other code doesn't know whether the Combatant is an AICombatant, but the object will still have that property and will behave correctly for its class.
Make it a Vehicle* and make each class implement type to return a constant indicating that class's type.
#property (nonatomic, strong) Vehicle* yourRide;
...
if (yourRide.type == VehicleConstant_Truck) {
Truck* yourTruck = (Truck*) yourRide;
NSLog(#"This truck %s a 4x4", yourTruck.is4x4 ? "is" : "isn't");
}
To make #vikingosegundo happy, an alternative approach is to do:
if ([yourRide isKindOfClass:[Truck class]]) {
instead of the if statement above.

OOP In Objective-C

I am familiar with OOP as I have been coding in Java for a while now, but I am having (syntax?) trouble in Objective-C. I have been looking at other posts on here but nothing has helped so far.
I have a class named "Play_Name.m" that has a method that sets a players name at the touch of a button and another method that gets the name and returns a string, (NSString*)get_name. I also have another class named "Play_ChooseChar.m" which is supposed to display the name entered in by calling the get_name function.
get_name returns the correct name when I call it in "Play_Name" (it's owner), but when I call it in "Play_ChooseChar" it returns (null).
//Play_Name code below
#import "Play_Name.h"
#interface Play_Name ()
#end
#implementation Play_Name
#synthesize playerName;
#synthesize textName;
-(IBAction)set:(id)sender {
[self setPlayerName:(self.textName.text)];
if([self.textName.text length] <= 0) {
playerName = #"Player";
NSLog(#"YOUR NAME: %#", playerName);
}
NSLog(#"YOUR NAME: %#", playerName);
}
//...........
#end
//Play_ChooseChar code below
#import "Play_ChooseChar.h"
#import "Play_Name.h"
#interface Play_ChooseChar ()
#end
#implementation Play_ChooseChar
#synthesize display_name;
#synthesize playname;
#synthesize boy;
#synthesize girl;
#synthesize isGirl;
#synthesize isBoy;
bool isGirl = FALSE;
bool isBoy = FALSE;
-(void)theName {
Play_Name *pN = [[Play_Name alloc] init];
[pN setPlayerName: pN.playerName];
NSLog(#"NAME: %#", pN.playerName);
self.display_name.text = pN.playerName;
//display_name.text = #"test";
[pN release];
//............
#end
So when I run it and enter my name, the print statement from "Play_ChooseChar" returns 'NAME: (null)'
Opening lecture: you seem to be throwing Objective-C conventions to the wind. Getters shouldn't refer to the act of getting — so you'd implement name, not get_name and almost the only verb you'll see is 'is', in the sense of isValid ala NSTimer. Objective-C also uses camel case, starting with a lower-case character so player_name should be playerName. Similarly your class should have a three-letter prefix (as Objective-C doesn't do namespaces) and also be camel case, e.g. ATPPlayName.
Lecture points aside, this:
Play_Name *play_name = [[Play_Name alloc] init];
creates a brand new instance of Play_Name. It's not the same as whatever instance you're using elsewhere. That instance doesn't have a name attached yet. So when you ask it for the name in the next line, it's nil.
You haven't really shown enough code to determine the problem. However, I would recommend using properties rather than methods which follow your own naming convention. For example:
#interface Player: NSObject
#property NSString* name;
#property NSString* character;
#end
The above defines a class Player with the properties name and character. Xcode will generate the appropriate accessor methods and instance variables that 'back' these properties. See the language reference for more details.
You should create properties, and xcode will automatically create getter & setter for you.
Have a look here:
putting design and code conventions aside:
when you create a new Play_Name instance, its get_name will return nil, obviously, because nowhere in the code have you called set_name before calling get_name.
You should first do:
[play_name set_name:#"john"];
And, assuming your set_name method is implemented correctly, [play_name get_name] should then return the correct value.
I second the others who recommend to use properties since it takes care of most memory mgmt nuances for you. You can read more about this here:
Objective-C: Declared Properties

How to retain my own objects and properties

I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.