Clarification on Asterisks and Underscores in Cocoa Syntax - objective-c

I recently picked up the BigNerdRanch book on Cocoa for Mac OSX and am looking for a good explanation around the use of asterisks * and underscores _ that seem to be inconsistently used throughout the language. Some examples:
These appear to be functionally equivalent:
NSString* myString;
NSString *myString;
Sometimes new variables get an underscore, while others dont:
NSString _myString;
NSString myString;
And sometimes it gets all crazy:
NSString *myString;
NSString *_myString;
I've also seen variations with asterisks in methods:
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender
willSpeakWord:(NSRange)characterRange
ofString:(NSString *)string;
So what is the functional use of the asterisk or the underscore, when should you use (or not use) either, and when should they be used in combination?

The * indicate a pointer, which all Objective-C objects are. (You pass around pointers to these objects in memory). At a basic level these are normal C pointers. If I remember correctly You could access some data in an Objective-C object by going object->data, just like you do with pointers to C structs.
The _ is a Cocoa (and some other languages) convention, meaning "a piece of data that should be considered private to this object".
Objective-C has a #private declaration, but it's also a relatively new addition to the language - if your code is more than 2 or 3 years old (or targeting much older versions of OS X) it might not use #private
Because of this initial lacking of language infrastructure, the _ is (often) used by the Cocoa community to mark "Hey, you probably shouldn't set or read this directly, please".
So:
When dealing with Objective-C classes you always need the * to follow the class name (like NSString), because they are always pointers. I'm confused about your NSString somestring line in your code - either that'll generate a complier warning or will crash when you try to use it
The _ indicates private data. You would do something like NSString* _name in a #interface section of your Objective-C class. You would use _name by itself if you were calling or operating on that data in a method in your class.
So say you created a Student class:
// Student.h
#interface Student : NSObject {
NSString* _name;
}
- (NSString*) name_as_caps;
#end
// Student.m
#implementation Student
- (NSString*) name_as_caps {
return [_name uppercase];
}
Here we declare a class with a "private" data member: _name. Our Student class needs to return this capitalized for some reason, so we created a method to do that, where we use _name and call the uppercase method on it.
We needed to refer to the type (or class name) or _name a few times here: once, to declare the variable. For name_as_caps we needed to say: this method returns a pointer to an NSString object, thus we used NSString *.

As an addendum to Ryan's answer, when you see something like
-(void)speechSynthesizer:(NSSpeechSynthesizer *)sender willSpeakWord:(NSRange)character
RangeofString:(NSString *)string;
the things like (NSSpeechSynthesizer *)sender just state the type of the argument - in this case NSSpeechSynthesizer*

Related

is there a way to have type-safe constants in Objective-C?

I am looking at a code base which is full of
NSString *const kTabChart = #"Charts";
NSString *const kTabNews = #"News";
and then
setSelectedTab:(NSString *)title;
...
someThingElse:(NSString *)title;
So these weak-typed NSString go far and all the way around the code and this just irritates my eyes. Enums would be better to some extent, but enums would not have the names available programmatically and I do not want to define all unrelated tab names from different views within the same enum {}
I wonder if there is a better way? I am dreaming of a way to make it something like
#interface PageTitle:NSSting;
PageTitle kTabChart = /some kind of initializer with #"Chart"/;
PageTitle kTabNews = /some kind of initializer with #"News"/;
I suspect that this would not play well with the whole "not a compile-time constant" constraint, but I wonder if there are tricks/patters/hacks to define constants of my own class type.
You should use NS_TYPED_ENUM as this makes it into a rawVlaue. More info https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/grouping_related_objective-c_constants
Sure, just think subclassing. First our class, which is a subclass of NSString:
#interface StringConstants : NSString
extern StringConstants * const kOptionApple;
extern StringConstants * const kOptionBlackberry;
#end
So we've defined StringConstants and a couple of global constants for it. To implement the class without any warnings just requires some casting:
#implementation StringConstants
StringConstants * const kOptionApple = (StringConstants *)#"Apple";
StringConstants * const kOptionBlackberry = (StringConstants *)#"Blackberry";
#end
And there is our set of constants. Let's test it:
- (void) printMe:(StringConstants *)string
{
NSLog(#"string: %#", string);
}
- (void) test
{
[self printMe:kOptionApple]; // Code completion offers the constants
[self printMe:#"Rhubarb"]; // Warning: Incompatible pointer types
[self printMe:(StringConstants *)#"Custard"]; // OK
}
You only get a warning, the code will run, as with other similar type errors.
You can of course repeat the pattern and produce one "class" per set of strings.
HTH
Addendum: It Is Safe (Trust Me For Now) and the Weak Enum
Concern has been raised in the comments that the above code is essentially dangerous, it is not. However in the general case the concerns raised are valid, it is safe here by design.
Note: This is being typed directly into SO. Please forgive the inevitable spelling & grammar errors, and the probable lack of good presentation, well defined explanatory arc, missing bits, redundant bits etc.
First let's add the missing comments to the above code, start with the implementation:
// The following *downcasts* strings to be StringConstants, code that
// does this should only appear in this implementation file. Use in
// other circumstances would effectively increase the number of "enum"
// values in the set, which rather defeats the purpose of this class!
//
// In general downcasting should only be performed after type checks to
// make sure it is safe. In this particular case *by design* it is safe.
StringConstants * const kOptionApple = (StringConstants *)#"Apple";
There are two different issues here
Is it safe at all - yes by design, trust me (for now); and
The addition of additional "enum" values
The second is covered by the second missing comment in the test code:
[self printMe:(StringConstants *)#"Custard"]; // OK :-( - go ahead, graft
// in a new value and shoot
// yourself in the foot if
// you must ;-)
The weak enum
Dealing with the second issue first, unsurprisingly this "enum" isn't bulletproof - you can add additional values on the fly. Why unsurprising? Because you can do it in (Objective-)C as well, not only is the language not strongly typed the enum types are the weakest of the lot. Consider:
typedef enum { kApple, kBlackberry } PieOptions;
How many valid values of PieOptions are there? Using Xcode/Clang: 2^32, not 2. The following is perfectly valid:
PieOptions po = (PieOptions)42;
Now while you should not write such obviously wrong code the need to convert between integers and enum values is common - e.g. when storing "enum" values in the tag field of UI controls - and thus the room for errors. C-style enumerations have to be used with discipline, and used that way are a good aid to program correctness and readability.
In the same way StringConstants must be used with discipline, no casting arbitrary strings - the equivalent of the 42 example above - and with discipline they have similar advantages and disadvantages to standard enumerations.
With the simple discipline of not casting arbitrary strings to StringConstants; something which is allowed only in the StringConstants implementation itself; this type gives you a completely safe "enumeration of string values" with compile-time warnings if used incorrectly.
And if you trust me you can stop reading now...
Addendum: Digging Deeper (Just Curious or We Don't Trust You)
To understand why StringConstants is completely safe (even adding additional values isn't really unsafe, though it may of course cause a program logic failure) we'll go through a number of issues about the nature of object-oriented programming, dynamic typing and Objective-C. SOme of what follows isn't strictly necessary to understand why StringConstants is safe, but you're someone with an inquiring mind aren't you?
Object reference casts don't do anything at runtime
A cast from one object reference type to another is a compile-time statement that the reference should be treated as being to an object of the destination type. It has no effect on the actual referenced object at runtime - that object has an actual type and it doesn't change. In the object-oriented model upcasting, going from a class to one of its superclasses, is always safe, downcasting, going in the reverse direction, may not (not is not) be safe. For this reason downcasting should be protected by tests in the cases it may be unsafe. For example given:
NSArray *one = #[ #{ #"this": #"is", #"a" : #"dictionary" } ];
The code:
NSUInteger len = [one.firstObject length]; // error, meant count, but NO compiler help at all -> runtime error
will fail at runtime. The result type of firstObject is id, which means any object type, and the compiler will let you call any method on references typed as id. The mistakes here are to not check the array bounds and that the retrieved reference is in fact a dictionary. A more bulletproof approach is:
if (one.count > 0)
{
id first = one.firstObject;
if ([first isKindOfClass:[NSDictionary class]])
{
NSDictionary *firstDict = first; // *downcast* to improve compile time checking
NSLog(#"The count of the first item is %lu", firstDict.count);
}
else
NSLog(#"The first item is not a dictionary");
}
else
NSLog(#"The array his empty");
The (invisible) cast is perfectly safe, protected as it is by the isKindOf: test. Accidentally type firstDict.length in the above code fragment and you will get a compile-time error.
However you only need to do this if the downcast might be invalid, if it cannot be invalid no tests are required.
Why can you call any method on references types as id?
This is where Objective-C's dynamic runtime message lookup comes into play. The compiler checks, to the best of its ability, for type errors at compile-time. Then at runtime another check is made - does the referenced object support the called method? If it does not a runtime error is generated - as occurs with the length example above. When an object reference is typed as id this is an instruction to the compiler to perform no compile-time check at all and leave it all to the runtime checks.
The runtime check is not checking the type of the referenced object, but instead whether it supports the requested method, which leads us to...
Ducks, NSProxy, Inheritance, et. al.
Ducks?!
In dynamic typing there is a saying:
If it looks like a duck, swims like a duck, and quacks like a duck, then it is a duck.
In Objective-C terms this means that at runtime if a referenced object supports the set of methods of type A then it is effectively an object of type A regardless of what it real type is.
This feature is used in many places in Objective-C, a notable example is NSProxy:
NSProxy is an abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet. Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy can be used to implement transparent distributed messaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensive to create.
With NSProxy you may think you have, say, an NSDictionary - something which "looks, swims and quacks" like an dictionary - but in fact you've not got one at all. The important points are:
It does not matter; and
It is perfectly safe (modulo coding errors if course)
You can view this ability to substitute one object for another as a generalisation of inheritance - with the later you can always use a subclass instance in lieu of a superclass one, with the former you can use any object in place of another as long as it "looks, swims and quacks" like the object it is standing in for.
We've actually gone further than we need, ducks are not really required to understand StringConstants, so let's get on:
When is a string an instance of NSString?
Probably never...
NSString is implemented by a class cluster - a collection of classes which all respond to the same set of methods that NSString does, i.e. they all quack like NSString. Now these classes may be subclasses of NSString, but in Objective-C there is no actual need for them to be.
Furthermore if you think you have an instance of NSString you may actually have an instance of NSProxy... But it does not matter. (Well it might impact performance, but it doesn't impact safety or correctness.)
StringConstants is a subclass of NSString, so it certainly is an NSString, except that NSString instances probably don't exist - every string is actually an instance of some other class from the cluster, which may or may not itself be a subclass of NSString. But it does not matter!
As long as instances of StringConstants quack like NSStrings should then they are NSStrings - and all the instances we have defined in the implementation do that as they are strings (of some type, probably __NSCFConstantString).
Which leaves us with the question is the defining of the StringConstants constants sound? Which is the same question as:
When is Downcasting Known To Be Always Safe?
First an example of when it is not:
If you have a referenced typed as NSDictionary * then it is not known to be safe to cast it to NSMutableDictionary * without first testing whether the reference is to an mutable dictionary.
The compiler will always let you do the cast, you can then at compile-time make calls to mutating methods without error, but at run-time there will be errors. In this case you must test before casting.
Note that the standard test, isKindOf:, is effectively conservative due to all those ducks. You may actually have a reference to an object which quacks like an NSMutableDictionary but is not an instance of it - so the cast would be safe but the test will fail.
What makes this cast unsafe in general?
Simple, it is not known whether the reference object responds to the methods that an NSMutableDictionary does...
Ergo, if you did know that the reference must respond to all the methods of the type you are casting to then the cast is always safe and no test is required.
So how do you know the reference must respond to all the methods of the target type?
Well one case is straightforward: If you have a reference typed as T you can it to a reference of type S safely without any checks whatsever if:
S is a subclass of T - so it quacks like a T; and
S adds no instance state (variables) to T; and
S adds no instance behaviour (new methods, overrides etc.) to T; and
S overrides no class behaviour
S may add class new class methods (not overrides) and global variables/constants without violating these requirements.
In other words S is defined as:
#interface S : T
// zero or more new class methods
// zero or more global variables or constants
#end
#implementation S
// implementation of any added class methods, etc.
#end
And We Made It...
Or did we, anybody still reading?
StringConstants is by design constructed so that string instances can be cast to it. This should only be done in the implementation, sneaking in additional "enum" constants elsewhere goes against the purpose of this class.
It is safe, indeed its not even scary :-)
No actual instances of StringConstants are ever created, each constant is an instance of some string class safely at compile-time masquerading as a StringConstants instance.
It provides compile-time checking that a string constant is from a pre-determined set of values, it is effectively a "string valued enumeration".
Yet Another Addendum: Enforcing Discipline
You cannot completely automatically enforce the discipline required to code safely in Objective-C.
In particular you cannot have the compiler prevent programmers from casting arbitrary integer values into enum types. Indeed, due to uses such as the tag fields of UI controls, such casts need to be allowed in certain circumstances - they cannot be totally outlawed.
In the case of StringConstants we cannot have the compiler prevent the cast from a string everywhere except in the implementation of the class itself, just as with enum extra "enum" literals can be grafted in. This rule requires discipline.
However if discipline is lacking the compiler can assist with preventing all the ways, other than casting, that can be used to create NSString values and hence StringConstant values as it is a subclass. In other words all the initX, stringX etc. variations can be marked as unusable on StringConstant. This is done by simply listing them in the #interface and adding NS_UNAVAILABLE
You don't need to do this, and the answer above does not, but if you need this assistance to your discipline you can add the declarations below - this list was produced by simply copying from NSString.h and a quick search & replace.
+ (instancetype) new NS_UNAVAILABLE;
+ (instancetype) alloc NS_UNAVAILABLE;
+ (instancetype) allocWithZone:(NSZone *)zone NS_UNAVAILABLE;
- (instancetype) init NS_UNAVAILABLE;
- (instancetype) copy NS_UNAVAILABLE;
- (instancetype) copyWithZone:(NSZone *)zone NS_UNAVAILABLE;
- (instancetype)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer NS_UNAVAILABLE;
- (instancetype)initWithCharacters:(const unichar *)characters length:(NSUInteger)length NS_UNAVAILABLE;
- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString NS_UNAVAILABLE;
- (instancetype)initWithString:(NSString *)aString NS_UNAVAILABLE;
- (instancetype)initWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2) NS_UNAVAILABLE;
- (instancetype)initWithFormat:(NSString *)format arguments:(va_list)argList NS_FORMAT_FUNCTION(1,0) NS_UNAVAILABLE;
- (instancetype)initWithFormat:(NSString *)format locale:(id)locale, ... NS_FORMAT_FUNCTION(1,3) NS_UNAVAILABLE;
- (instancetype)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList NS_FORMAT_FUNCTION(1,0) NS_UNAVAILABLE;
- (instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding NS_UNAVAILABLE;
- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding NS_UNAVAILABLE;
- (instancetype)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer NS_UNAVAILABLE;
+ (instancetype)string NS_UNAVAILABLE;
+ (instancetype)stringWithString:(NSString *)string NS_UNAVAILABLE;
+ (instancetype)stringWithCharacters:(const unichar *)characters length:(NSUInteger)length NS_UNAVAILABLE;
+ (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString NS_UNAVAILABLE;
+ (instancetype)stringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2) NS_UNAVAILABLE;
+ (instancetype)localizedStringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2) NS_UNAVAILABLE;
- (instancetype)initWithCString:(const char *)nullTerminatedCString encoding:(NSStringEncoding)encoding NS_UNAVAILABLE;
+ (instancetype)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc NS_UNAVAILABLE;
- (instancetype)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error NS_UNAVAILABLE;
- (instancetype)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error NS_UNAVAILABLE;
+ (instancetype)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error NS_UNAVAILABLE;
+ (instancetype)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error NS_UNAVAILABLE;
- (instancetype)initWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error NS_UNAVAILABLE;
- (instancetype)initWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc error:(NSError **)error NS_UNAVAILABLE;
+ (instancetype)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error NS_UNAVAILABLE;
+ (instancetype)stringWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc error:(NSError **)error NS_UNAVAILABLE;
Have you thought about the #define macro?
#define kTabChart #"Charts"
During the pre-processing step of compilation, the compiler will swap out all kTabChart w/ your desired constant.
If you want constants of your own custom class, then you will have to use const as user #JeremyP says in the linked answer

I do not understand Objective-C Initializer for a class.

This code is from the Sams Teach Yourself Swift book, Chapter 21. The Song.h file contains the following code:
//Song.h
#import <Foundation/Foundation.h>
#interface Song : NSObject;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *artist;
#property (nonatomic, strong) NSNumber *rating;
- (instancetype)initWithTitle:(NSString *)title artist:(NSString *)artist rating:(NSNumber *)number;
#end
To my understanding, the - (instancetype) creates an instance method, returning an instancetype. The two (NSString *)s declare that the parameter will be an NSString. I assume that the word title immediately following the first (NSString *) is the parameter name, same with the artist following the (NSString *). What is the initWithTitle: and the artist:?
You pretty much have it correct.
An Obj-C instance method begins with a hyphen, "-" followed by the return type in parentheses. A Class method, begins with a plus "+" but is otherwise the same.
That's followed by the rest of the method signature, which can include multiple parameters. Each parameter is preceded by a colon ":", then the required type for the argument/parameter in parentheses, e.g. NSString *, which is followed finally an internal name for the value that will be passed in. You read the entire method name by stating each parameter...
initWithTitle:artist:rating
Read as a sentence, you're saying:
"Inititialize a Song instance with a title (that's an NSString*), an artist (also an NSString*), and a rating (this requires an NSNumber *)"
-(returnType)firstPartofMethodNameThatTakestheArgument:(NSString *)argument1 andArgumentTwo:(NSString *)argument2
The instanceType is a relatively new alternative for id which meant the return type could effectively be anything. This instead ensures that it can only be an instance of the type containing the method, in this case a Song.
As for the duplicate argument names... The first part "artist: is the external name that appears when you call the method (if you use code completion for example, that's what shows up). The part after the argument's type (NSString *)artist is the internal name that will be used inside the method implementation. Those can be the same, but they don't have to be.
Swift has a similar construction, but with more options where you can choose to write different internal and external parameter names, or just use 1 (or use in-out parameters whose values chance, use variadic parameters that can be an arbitrary number of elements, etc - look into Swift Functions for more details on those topics).
func initWith(externalTitle internalTitle:String, #artist:String, #rating:Int) -> Song
//When calling, you'd see "externalTitle:artist:rating"
//but in the method implementation you'd use "internalTitle" instead.
instancetype is a replacement for the id (and in fact the compiler coverts id to instancetype for init methods at compile time) or specific type class usually returned by init methods and can't be used anywhere else. It allows the compiler to check that assignments from that init method are the appropriate type while still allowing subclasses to inherit initializers. So this init method most likely takes the initial values and assigns them to the properties.
It is the method's signature. In other words ..this is how the method is named.
Btw. "instancetype" is a compiler keyword, that represents the instance's type, so actually the method will return a Song instance.
- initWithTitle:artist:rating: is the method's name, or in Objective-C terms, selector. title, artist and rating are parameter names.
As for - (instancetype), the minus sign - means it's an instance method (class methods begin with a plus sign +), while instancetype is a return type of a method. It's just a keyword that tells the compiler this method will always return an object of type of class on which it was called. If you want to know more about it, I suggest reading the NSHipster post about instancetype.
You said:
To my understanding, the - (instancetype) creates an instance method, returning an instancetype.
The - designates an instance method. The instancetype is a special keyword designating that it returns an instance of the class, a Song instance in this case.
The two (NSString *)s declare that the parameter will be an NSString.
Yes, the two (NSString *) references indicate that the first two parameters are string values. The following (NSNumber *) indicates that the third parameter is a number object.
I assume that the word title immediately following the first (NSString *) is the parameter name, same with the artist following the (NSString *). What is the initWithTitle: and the artist:?
The word immediately following the (NSString *) is the name of the parameter used within the implementation of that method.
Consider the declaration:
- (instancetype)initWithTitle:(NSString *)title artist:(NSString *)artist rating:(NSNumber *)number;
This declares a method called initWithTitle:artist:rating:, that takes three parameters, a title, artist, and rating. So if you wanted to create a song called "Ticket to Ride" by the "Beatles" and a rating of 5, you would call this method with something like:
Song *song = [[Song alloc] initWithTitle:#"Ticket to Ride" artist:#"Beatles" rating:#5];

multiple custom objects with same properies

i have 7 custom objects with the same properties, createDate and modifiedDate. can i create a method that accepts Object1 but actually takes all 7 objects?
right now, this works:
[self setCreateAndModifiedTimeWithEvent:((Object1 *) object2
WithCreateDate:[[eventsArray objectAtIndex:i] objectForKey:#"create_date"]
AndModifiedDate:[[eventsArray objectAtIndex:i] objectForKey:#"modified_date"]];
.h file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
.m file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp
{
object.A = #"Hello,";
object.B = #"World";
}
this would cut back on good chuck of lines of code.
i know you can do this sort of thing with UIView and its subclasses. say i have a
UITextField myTextField.
i can do
((UIScrollView *)myTextField).tag = 2;
is there anything inherently bad about typecasting my objects like this or is it acceptable?
Like Joe said, you'd be better off with something like this:
#interface DatedObject : NSObject
#property NSDate *createDate;
#property NSDate *modifiedDate;
#end
#implementation DatedObject
#synthesize createDate;
#synthesize modifiedDate;
#end
Then have each of the 7 classes inherit from the DatedObject base class. Inheritance is a fundamental part of Object Oriented Programming, and you should learn to use it (wisely).
Then your method can be:
-(void) setCreateAndModifiedTimeWithEvent:(DatedObject *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
You could also do this with a protocol, but the nice thing about using a base class that the other classes inherit from is that you only have to implement this functionality in one place. If the 7 classes don't all currently inherit from the same base class (which would end up being the superclass of DatedObject), a protocol is probably the way to go. In that case, you can declare your method like this:
-(void) setCreateAndModifiedTimeWithEvent:(id<DatedObjectProtocol>)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
One of the big advantages to these two approaches over what you've posted in your question is that you get more help from the compiler in catching places where your code sends a message to an object that doesn't respond to it.
Andrew's answer is correct.
But, if for some reason you don't want to create a common base class or a protocol, you could always set the type of the method parameter to id, like this:
-(void) setCreateAndModifiedTimeWithEvent:(id)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
Parameters of type id don't do any type checking at compile time (like the values in an NSArray) so you can call any method you want on them without generating compiler warnings (this is obviously quite dangerous if you aren't careful).
You can't use dot notation on id variable without casting, but it's better to cast from an id to a concrete type than to cast from a different unrelated type.
It doesn't actually make any difference except to your code readability though.

Understanding self in Objective-C

The code below is from an iTunes U course on iPhone dev in Objective-C. I've read the Apple documentation and it's all very very clear with the exception of self. I sort of understand self to be a pointer to myself, but what exactly does that mean? In the code below what exactly does self mean? What is the difference between self.topSpeed and self.nearestWormhole in the implementation file or does self refer to the same thing on both occasions? Does self.topSpeed refer to Planet * and self.nearestWormhole refer to Wormhole * ? Thanks to anyone who answers, I've learned C and now trying to learn OOP so any input is appreciated.
(Header file)
#import "Vehicle.h"
#import "Planet.h"
#interface Spaceship : Vehicle
#property (nonatomic) double topSpeed;
- (void)orbitPlanet:(Planet *)aPlanet
atAltitude:(double)km;
#end
(Implementation file)
#import "Spaceship.h"
#interface Spaceship()
#property (nonatomic, strong) Wormhole *nearestWormhole;
#end
#implementation Spaceship
#synthesize topSpeed = _topSpeed;
#synthesize nearestWormhole = _nearestWormhole;
- (void)setTopSpeed:(double)speed
{
if ((speed < 1) && (speed > 0)) _topSpeed = speed;
}
- (void)orbitPlanet:(Planet *)aPlanet atAltitude:(double)km
{
double speed = self.topSpeed;
if (speed > MAX_RELATIVE) speed = MAX_RELATIVE;
[self.nearestWormhole travelToPlanet:aPlanet
atSpeed:speed];
}
#end
self (or this in C++) refers to the object which is executing the method (or "on which the method is being invoked").
Suppose I have a room with three people, Arthur, Betty, and Ziggy, and a box of hats. We also define that
Arthur's teacher is Betty.
Betty's teacher is Ziggy.
Ziggy does not have a teacher.
I want to give the following set of instructions to all three people:
1. Put a hat on Ziggy's head.
This is pretty easy. "Ziggy" means the same person to Arthur, Betty, and even Ziggy. No matter who follows this instruction the same person receives the hat.
2. Put a hat on the head of your teacher, if you have one.
This instruction will have a different effect depending on who's following it, because teacher refers to someone different for each of the three. But each can ask him/herself "who is my teacher, if I have one?" and find that person.
But the next thing I want is for Arthur to put a hat on Arthur's head, Betty to put a hat on Betty's head, and Ziggy to put a hat on Ziggy's head. We can't refer to that person by name (like Ziggy) because it depends on who is doing it. Suppose we treat it like "teacher" and establish a variable "foo" such that Arthur's foo is Arthur, and Betty's foo is Betty… but it should be obvious that the idea we are really expressing is that Ziggy's foo is Ziggy, and Jack's foo would be Jack, and Skip's foo would be Skip… do we really need to establish a "foo"? No! Everyone has a foo: it's your self. So let's define an implicit variable "self" that is not declared anywhere but always refers to the person carrying out the action.
3. Put a hat on the head of your self.
This works for Arthur, Betty, Ziggy, and even Jack. It works for anyone.
In your code self refers to the Spaceship whose topSpeed needs to be accessed. You create many Spaceships and each needs to know the topSpeed of that one Spaceship which exists (we know it does because it's calling the method) but has no name (like myWingman.topSpeed) - one's self.
Cristian, I'll offer you a different tack on this. You say you know C, let's start there. If you needed to implement fractions you'd use a struct, and let's assume for some reason you decide to dynamically allocate your fractions. You have something like this:
typedef struct { int numerator; int denominator; } Fraction;
Fraction *newFraction(int numer, int denom)
{
Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
result->numerator = numer;
result->denominator = denom;
return result;
}
Fraction *multiplyFraction(Fraction *left, Fraction *right)
{
Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
result->numerator = left->numerator * right->numerator; // multiple (ignoring reduction)
result->denominator = left->denominator * right->denominator;
return result;
}
And you'd use it like:
Fraction *half = newFraction(1, 2);
Fraction *twothirds = newFraction(2, 3);
Fraction *onethird = multiplyFraction(half, twothirds); // results is 2/6 as we don't reduce in this example
This is the ADT - abstract data type - style of programming. You declare a data type whose content is private (the "abstract" part) to the functions you will provide, and a bunch of functions.
At the basic level what object-oriented programming does is just invert the way you look at this. Instead of "call function multiplyFraction passing two fractions" you say "pass the message multiplyFraction, along with a fraction, to a fraction". Using Objective-C syntax the last line above:
Fraction *onethird = multiplyFraction(half, twothirds);
becomes:
Fraction *onethird = [half multiplyFraction:twothirds];
Under the hood this "method send" just becomes a "function call" - Objective-C does a bit of work to locate multipleFraction and then calls it passing it both half and twoThirds.
Almost there! Now to match the changed syntax for the call Objective-C also changes the syntax of the definition of multiplyFraction:
- (Fraction *) multiplyFraction:(Fraction *)right
{
Fraction *result = [Fraction new]; // allocate
result->numerator = ????->numerator * right->numerator;
result->denominator = ????->denominator * right->denominator;
return result;
}
But what do you write for ????. As you'll see the syntax only names the second parameter (right), there is no name given for the first (which was left). Objective-C hides the passing of this parameter, every method takes at least one parameter - it is the "object" (rather than "ADT") that the method is sent to. It needs a name so you can refer to it, that name is self:
- (Fraction *) multiplyFraction:(Fraction *)right
{
Fraction *result = [Fraction new]; // allocate
result->numerator = self->numerator * right->numerator;
result->denominator = self->denominator * right->denominator;
return result;
}
And this is essentially it - self is the name of the first argument.
Object-oriented languages build upon this base, for example:
they had direct access to "instance" variables - the "fields" of the original struct;
they change some more syntax - e.g. #interface... replaces struct...; and rather than list the methods (functions) after the type (struct) in the header they are listed inside of it (the `#interface);
they usually add inheritance (though some ADT languages have that as well);
etc.
But under the hood an Objective-C class is implemented as a C struct...
HTH
Objective C emphasizes using getters and setters. To make things simpler, it even generates getters and setters when you #synthesize something.
So
self.topSpeed
accesses the getter for topSpeed. If you omit the "self" part, then it is equivalent to accessing the instance variable(ivars) directly (bad practice).
The reason for having a underscore before the variable name is also to make a clear differentiation between instance variable and the getter for the instance variable. This way, we cannot accidentally refer to topSpeed without "self".
You need to use self to access variable in all places except:
init
dealloc
Hope that helps.
self is indeed a pointer reference to the instance of the class that is running the code. In this case, self would be a reference to an instance of the Spaceship class.
When you reference self in a class method (which is very possible and an acceptable behavior), you are actually referencing a singleton instance representing the class. You can also get this singleton instance by calling [Spaceship class]. In practice, you'd use self like this mostly in factory methods when you need to allocate a new instance.
What you seem more confused about is syntax regarding other classes. You asked:
Does self.topSpeed refer to Planet * and self.nearestWormhole refer to
Wormhole * ?
Wormhole *nearestWormhole represents an instance of the Wormhole class, named nearestWormhole. So, when you use self.nearestWormhole, that is a pointer to a instance of the Workhole class. Inside the Spaceship class you could actually use _nearestWormhole or self.nearestWormhole to access that pointer. Other classes might call something like spaceship.nearestWormhole, which is using the accessor.
'self' refers to the instance of the current class, i.e. in your example it would refer to an instance of the Spaceship class. Because 'self' always refers to an instance of the class, it's not possible to call upon self in class methods.

Do Objective-C Category names do anything?

A class can be extended in Objective C using a category such as:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
In this small example, I would be adding the method myFabulousAddition to NSString. I could then call it by [anNSString myFabulousAddition] just as if it were part of the NSString set of methods. Great and useful.
In the Apple documents regarding Categories, the docs state:
There’s no limit to the number of
categories that you can add to a
class, but each category name must be
different, and each should declare and
define a different set of methods.
What if you have something like this:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
#interface NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition; // a DIFFERENT fabulous additional method
// BUT with same name as the other category
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
#implementation NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition {
// do something equally fabulous, but DIFFERENT...
}
#end
The lack of a name in the parenthesis indicates that the form is an extension to the class, like so:
#interface MyObject () // No name -- an extension vs category to MyObject
- (void)setNumber:(NSNumber *)newNumber;
#end
Does the category name have any meaning to the compiler or linker? Is the category name part of the method signature in anyway or is it part of a primitive namespace? If the category name is meaningless, how do you know if you are about to stomp on another method and get undefined behavior?
The way to avoid stomping on methods is to prefix your category method names, like this:
#interface NSString (MyCompanyCategoryName)
- (NSString *)MYCO_fabulousAddition;
#end
If you get a collision of method names from different categories, then which one 'wins' at run time is completely undefined.
The name of a category is almost entirely useless, with the exception being that the nameless category (i.e. ()) is reserved for class extensions. Methods from class extensions are supposed to be implemented in the class' main #implementation.
The category name doesn't mean anything special, it's just an identifier. Unless the linker (or runtime loader) decides to give you a warning, there is no way to tell that multiple categories are defining the same method.
The behavior is (largely) unpredictable - one of the categories will win out, but you can't tell which one. Also, I think it's well possible you will start out with one implementation and end up with another one (if the second category is loaded after the first).
It certainly acts as an identifier, from the programmer's point of view. In the compiler point of view category methods are simply added as an extension of the class ( from which it is extending), regardless of the name.
And yes you can add categories of the same class with the same identifiers, even with same functions. But you definitely can't override any function because categories are just part of the class once you define them ( Just like you can't override a function of a class from within that class ).
As they are being added at runtime, they don't raise any error and only at runtime compiler selects the function, which is totally unpredictable.
i believe that they don't have any meaning. You don't really use them in your code ... Since they are categories and ... the semantic of a category ... is just to categorize something, i think this is somewhat logical ...
I would say they just simply gather the methods ...
On the other hand your question is very valid ... You DON'T KNOW if you override a method. If you are in the same project then the compiler issues a warning (or an error ? i don't remember), however if you are overriding a method from a library, then .. you are out of luck ...