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
Related
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];
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)
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.
There was a question couple years back re instance vs class methods.
It was illustrated with the code below. I understand for the most part, except why do I need both instance variable "age" and instance method "age"?
Won't getter and setter for instance variable "age" be created with #synthetize?
Static int numberOfPeople = 0;
#interface MNPerson : NSObject {
int age; //instance variable
}
+ (int)population; //class method. Returns how many people have been made.
- (id)init; //instance. Constructs object, increments numberOfPeople by one.
- (int)age; //instance. returns the person age
#end
#implementation MNPerson
- (id)init{
if (self = [super init]){
numberOfPeople++;
age = 0;
}
return self;
}
+ (int)population{
return numberOfPeople;
}
- (int)age{
return age;
}
#end
main.m:
MNPerson *micmoo = [[MNPerson alloc] init];
MNPerson *jon = [[MNPerson alloc] init];
NSLog(#"Age: %d",[micmoo age]);
NSLog(#"%Number Of people: %d",[MNPerson population]);
(Original code from #micmoo)
The instance method age is for encapsulation. It lets subclasses override the method, providing a different implementation if they need to. For example, a subclass may want to calculate the age based on the initial date and the current date, rather than storing it. If you use an instance variable, subclasses would have no option to override age; if you add an instance method, then subclasses would be able to provide new implementation.
Another advantage is that you cannot write to age: the users of your class can get the age, but they cannot set it.
Won't getter and setter for instance variable "age" be created with #synthetize?
The #synthesize requires a property declaration, which is missing from the class. Properties are relatively new to the language, which may explain the reason why they are not used in the code that you found.
The current way of doing the same thing is declaring a property instead of an ivar and an accessor, and skipping the #synthesize altogether:
#property (nonatomic, readonly) int age;
You can write to age from inside the class by assigning _age, the backing variable created automatically; the users can read the value by using either [obj age] or obj.age syntax.
This code was apparently written prior to the introduction of declared properties and the #sythesize directive, which were introduced with so-called "Objective-C 2.0" at the time of Mac OS X Leopard. A brief introduction is available at The Cacao, which will demonstrate to you what the old way looked like.
Yes, it would be far better to do it the modern way, but in those dark ages, we had to declare every ivar in the class's interface, and to write every setter and getter manually. Every single one, uphill both ways, in the snow, with no boots.
I want to create an object called Note . Then I want to assign some values to it's fields and display them in the console to verify that all of this works properly.
Note.h
#import <Foundation/Foundation.h>
#interface Note : NSObject
{
NSNumber *position;
NSString *syllable;
}
#property(nonatomic, retain)NSNumber *position;
#property(nonatomic, retain)NSString *syllable;
#end
Note.m
#import "Note.h"
#implementation Note
#dynamic position;
#dynamic syllable;
#end
After this , in another class I want to assign some values to the fields .
-(void) configNote:(Note*)not
{
not = [Note alloc];
[not setPosition:[NSNumber numberWithInt:2]];
[not setSyllable:#"Twin-"];
}
.....
Note *note;
[self configNote:note];
NSLog(#" pos : %d syl : %# ",[[note position] integerValue],[note syllable]);
I tried to use #synthesize instead of #dynamic but still nothing changes . The reason of the error is : -[Note setPosition:]: unrecognized selector sent to instance 0x733d060
init your note and use custom init method to initialize ivars and change dynamic to synthesize
and for better use this init to initialize your varibales
- (id)initWithPosition:(NSNumber*)pos andSyllable:(NSString*)syl {
self = [super init];
if (self) {
self.position = pos;
self.syllable= syl;
}
return self;
}
Since your question is quite basic and fundamental you might want to check out this Tutorial on cocoadevcentral. It's very well done and teaches you some of the basics when dealing with objects.
Your problem is that you are passing the Note object pointer to configNote: by value rather than by reference. Inside of configNote: when you set not to a newly allocated Note object, you are actually setting the local variable not to that value. What your NSLog call outside of your configNote: object actually receives is original note value prior to the call to configObject:.
To get what I believe you desire, either more the Note object allocation outside of the configObject: method, or pass the Note object pointer to configObject: by reference.
If you are using ARC, try "strong" instead of "retain".