Declaring and implementing a method that itself executes one line of code - objective-c

I've many times seen a case where a programmer needs to assign some value (Object or primitive type, does not matter). And let's say this value is an NSString and can be obtained from the following expression
[myObject description]// returns NSString
But for some reason I've seen many people declare another method that itself returns an NSString and executes the above command only. Like:
-(NSString*)getDescription{
return [myObject description];
}
Is this just a matter of preference, or is is there some benefit from it?

Is this just a matter of preference, or is is there some benefit from it?
Those one line wrappers are often used to:
introduce behavior of a method that is meant to be overridden
or (more frequently) to simplify the program. If the method did not exist, you may find the complexity of the program grows. It serves to demonstrate intent, for clarity, documentation, and to minimize redundant implementations (simplifying the program).

There is definitely some "benefit" of creating a method or even better, overriding the "standard" NSObject description method..
If you have a custom NSObject for example and override the +(NSString *)description method you can then return information directly inside that object.
Take for example the following was overwritten in the NSObject we called foo.
+ (NSString *)description {
return #"Hello there";
}
Now, if you ever called [foo description] it would return the string "Hello there".
However, if you just returned description without overwriting the description method, it'd return something like <foo>0x12234 or something.
So yeah, it definitely has a lot of benefit to overriding a custom NSObject description.

Related

Empty method name, what does this actually do?

I'm currently learning myself objective-c and iOS programming and found myself stuck with non-working code due to this subtle error for an hour.
Consider the following code:
#property (strong, nonatomic) NSString *name;
- (NSString *):name { return #"Some name"; }
At first glance (and for anyone new) this looks like an overridden getter for the name property. But theres a very subtle : that shouldn't be there. You get no warning/error from the compiler/parser/runtime here, so my question is what does this actually end up as?
I tried to figure a way of calling this method once I saw the error, but didn't succeed in my few attempts.
The method signature - (NSString *):name breaks down to the following:
- It is an instance method (versus a class method with a +).
(NSString *) It returns a string.
: If you were to speak the name of this method, it would simply be called "colon". : tells the compiler that your method accepts one parameter as well.
name There is a parameter called name.
When you don't specify a type, the compiler assumes you meant id, so this method actually fleshes out to be - (NSString *):(id)hello
A valid call to this method would be: [self :#"hello"].
You can do really weird things because : is a valid name for a method, and the compiler assumes id. You could, if you really wanted to, have a method called - :::. The compiler would assume you meant - (id):(id):(id):(id), a method that returns an object of type id and takes three parameters of type id. You'd call it like so: [self :#"hello" :anObject :myObject];
A method declare like the one you posted is rare (and poor style, imo). Objective-C is supposed to be verbose. Methods break down like this:
First character: Either - or +. - means it is an instance method, + means it is a class method.
Value in parentheses: The return type of the method. In your example, the method returns an (NSString *).
The rest (before the curly braces) is the method name along with any parameters they take. You could have a name with no parameters, in which case the method name would not have a : in it. Such as - (void) reload; This would be a method that doesn't return a value and takes no parameters.
If your method takes parameters, they will be mixed into the method name and usually will declare the type (unlike your example). Such as - (NSString *) reverseString:(NSString *) stringToReverse; In this example your method name would be reverseString: it takes one parameter, an NSString* that will be called stringToReverse in the method definition.
Usually, if you see a : with no type it will be a case like - (float) addThreeValues::: This method returns a float and takes 3 parameters. This would be an appropriate definition because the three values don't matter what order they are provided because we are just adding them.

Would it be beneficial to begin using instancetype instead of id?

Clang adds a keyword instancetype that, as far as I can see, replaces id as a return type in -alloc and init.
Is there a benefit to using instancetype instead of id?
Yes, there are benefits to using instancetype in all cases where it applies. I'll explain in more detail, but let me start with this bold statement: Use instancetype whenever it's appropriate, which is whenever a class returns an instance of that same class.
In fact, here's what Apple now says on the subject:
In your code, replace occurrences of id as a return value with instancetype where appropriate. This is typically the case for init methods and class factory methods. Even though the compiler automatically converts methods that begin with “alloc,” “init,” or “new” and have a return type of id to return instancetype, it doesn’t convert other methods. Objective-C convention is to write instancetype explicitly for all methods.
Emphasis mine. Source: Adopting Modern Objective-C
With that out of the way, let's move on and explain why it's a good idea.
First, some definitions:
#interface Foo:NSObject
- (id)initWithBar:(NSInteger)bar; // initializer
+ (id)fooWithBar:(NSInteger)bar; // class factory
#end
For a class factory, you should always use instancetype. The compiler does not automatically convert id to instancetype. That id is a generic object. But if you make it an instancetype the compiler knows what type of object the method returns.
This is not an academic problem. For instance, [[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData] will generate an error on Mac OS X (only) Multiple methods named 'writeData:' found with mismatched result, parameter type or attributes. The reason is that both NSFileHandle and NSURLHandle provide a writeData:. Since [NSFileHandle fileHandleWithStandardOutput] returns an id, the compiler is not certain what class writeData: is being called on.
You need to work around this, using either:
[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];
or:
NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];
Of course, the better solution is to declare fileHandleWithStandardOutput as returning an instancetype. Then the cast or assignment isn't necessary.
(Note that on iOS, this example won't produce an error as only NSFileHandle provides a writeData: there. Other examples exist, such as length, which returns a CGFloat from UILayoutSupport but a NSUInteger from NSString.)
Note: Since I wrote this, the macOS headers have been modified to return a NSFileHandle instead of an id.
For initializers, it's more complicated. When you type this:
- (id)initWithBar:(NSInteger)bar
…the compiler will pretend you typed this instead:
- (instancetype)initWithBar:(NSInteger)bar
This was necessary for ARC. This is described in Clang Language Extensions Related result types. This is why people will tell you it isn't necessary to use instancetype, though I contend you should. The rest of this answer deals with this.
There's three advantages:
Explicit. Your code is doing what it says, rather than something else.
Pattern. You're building good habits for times it does matter, which do exist.
Consistency. You've established some consistency to your code, which makes it more readable.
Explicit
It's true that there's no technical benefit to returning instancetype from an init. But this is because the compiler automatically converts the id to instancetype. You are relying on this quirk; while you're writing that the init returns an id, the compiler is interpreting it as if it returns an instancetype.
These are equivalent to the compiler:
- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;
These are not equivalent to your eyes. At best, you will learn to ignore the difference and skim over it. This is not something you should learn to ignore.
Pattern
While there's no difference with init and other methods, there is a difference as soon as you define a class factory.
These two are not equivalent:
+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
You want the second form. If you are used to typing instancetype as the return type of a constructor, you'll get it right every time.
Consistency
Finally, imagine if you put it all together: you want an init function and also a class factory.
If you use id for init, you end up with code like this:
- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
But if you use instancetype, you get this:
- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
It's more consistent and more readable. They return the same thing, and now that's obvious.
Conclusion
Unless you're intentionally writing code for old compilers, you should use instancetype when appropriate.
You should hesitate before writing a message that returns id. Ask yourself: Is this returning an instance of this class? If so, it's an instancetype.
There are certainly cases where you need to return id, but you'll probably use instancetype much more frequently.
There definitely is a benefit. When you use 'id', you get essentially no type checking at all. With instancetype, the compiler and IDE know what type of thing is being returned, and can check your code better and autocomplete better.
Only use it where it makes sense of course (i.e. a method that is returning an instance of that class); id is still useful.
Above answers are more than enough to explain this question. I would just like to add an example for the readers to understand it in terms of coding.
ClassA
#interface ClassA : NSObject
- (id)methodA;
- (instancetype)methodB;
#end
Class B
#interface ClassB : NSObject
- (id)methodX;
#end
TestViewController.m
#import "ClassA.h"
#import "ClassB.h"
- (void)viewDidLoad {
[[[[ClassA alloc] init] methodA] methodX]; //This will NOT generate a compiler warning or error because the return type for methodA is id. Eventually this will generate exception at runtime
[[[[ClassA alloc] init] methodB] methodX]; //This will generate a compiler error saying "No visible #interface ClassA declares selector methodX" because the methodB returns instanceType i.e. the type of the receiver
}
You also can get detail at The Designated Initializer
**
INSTANCETYPE
**
This keyword can only be used for return type, that it matches with return type of receiver. init method always declared to return instancetype.
Why not make the return type Party for party instance, for example?
That would cause a problem if the Party class was ever subclassed. The subclass would inherit all of the methods from Party, including initializer and its return type. If an instance of the subclass was sent this initializer message, that would be return? Not a pointer to a Party instance, but a pointer to an instance of subclass. You might think that is No problem, I will override the initializer in the subclass to change the return type. But in Objective-C, you cannot have two methods with the same selector and different return types (or arguments). By specifying that an initialization method return "an instance of the receiving object," you would never have to worry what happens in this situation.
**
ID
**
Before the instancetype has been introduced in Objective-C, initializers return id (eye-dee). This type is defined as "a pointer to any object". (id is a lot like void * in C.) As of this writing, XCode class templates still use id as the return type of initializers added in boilerplate code.
Unlike instancetype, id can be used as more than just a return type. You can declare variables or method parameters of type id when you are unsure what type of object the variable will end up pointing to.
You can use id when using fast enumeration to iterate over an array of multiple or unknow types of objects. Note that because id is undefined as "a pointer to any object," you do not include an * when declaring a variable or object parameter of this type.
The special type instancetype indicates that the return type from the init method will be the same class as the type of object it is initializing (that is, the receiver of the init message). This is an aid for the compiler so that it can check your program and flag potential
type mismatches—it determines the class of the returned object based on context; that is, if you’re sending the init message to a newly alloc’ed Fraction object, the compiler will infer that the value returned from that init method (whose return type has been declared as type instancetype) will be a Fraction object. In the past the return type from an initialization method was declared as type id. This new type makes more sense when you consider subclassing, as the inherited initialization methods cannot explicitly define the type of object they will return.
Initializing Objects, Stephen G. Kochan, Programming in Objective-C, 6th Edition

Arguments by reference in Objective-C

I'm trying to pass an NSString by reference but it doesn't work.
This is the function:
+(void)fileName:(NSString *) file
{
file = #"folder_b";
}
and this is the call:
NSString *file;
[function fileName:file];
nslog(#"%#",file); // and there is nothing in the string....
What I must do to pass my string by reference?
If you want to return a value, then return a value. Pass by reference in Cocoa/iOS is largely limited to NSError**.
Given:
+(void)fileName:(NSString *) file
Then do:
+(NSString *) fileName;
And be done with it.
If you need to return more than one value at a time, that begs for a structure or, more often, a class.
In Objective-C, pass by reference smells like you are doing it wrong.
Pass by reference in Objective-C is reserved largely for returning NSError* information about a recoverable failure, where the return value of the method itself indicates whether or not the requested task succeeded or failed (you can pass NULL as the NSError** argument to allow the method to optimize away creating said error metadata).
Pass by references is also used to retrieve interior state of objects where the return value is effectively a multi-value. I.e. methods from AppKit like the following. In these cases, the pass-by-reference arguments are typically either optional or are acting as secondary return values.
They are used quite sparingly across the API. There is certainly use for pass by reference, but -- as said above -- doing so should be quite rare and rarer still in application code. In many cases -- and in some of the cases below, potentially -- a better pattern would be to create a class that can encapsulate the state and then return an instance of said class instead of pass by reference.
NSWorkspace.h:- (BOOL)getInfoForFile:(NSString *)fullPath application:(NSString **)appName type:(NSString **)type;
NSTextView.h:- (void)smartInsertForString:(NSString *)pasteString replacingRange:(NSRange)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString;
NSAttributedString.h:- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
NSNib.h:- (BOOL)instantiateWithOwner:(id)owner topLevelObjects:(NSArray **)topLevelObjects NS_AVAILABLE_MAC(10_8);
NSSpellChecker.h:- (NSRange)checkGrammarOfString:(NSString *)stringToCheck startingAt:(NSInteger)startingOffset language:(NSString *)language wrap:(BOOL)wrapFlag inSpellDocumentWithTag:(NSInteger)tag details:(NSArray **)details NS_AVAILABLE_MAC(10_5);
I believe you're looking for:
+ (void)fileName:(NSString **)file
{
*file = #"folder_b";
}
What's really done here is we're working with a pointer to a pointer to an object. Check C (yup, just plain C) guides for "pointer dereference" for further info.
(...But as has been pointed out repeatedly, in this particular example, there's no reason to pass by reference at all: just return a value.)
Passing a pointer to your object is the Objective C (and C) way of passing by reference.
I agree with 'bbum' that a perceived need to pass by reference is a signal to think about what you are doing; however, it is by no means the case that there are not legitimate reasons to pass by reference.
You should not create classes willy-nilly every time you have a function or method that needs to return more than one value. Consider why you are returning more than one value and if it makes sense to create a class for that then do so. Otherwise, just pass in pointers.
-Just my 2 cents
Try this
+(void)filename:(NSString **)file {
*file=#"folder_b";
}
and send the file as &file like:
NSString *file;
[function fileName:&file];
nslog(#"%#",file);
hope this will work.
I suspect this is because NSString is immutable. Have you tried NSMutableString?

Using (id) in Objective-C

I have a function that I want to operate on two different custom objects. My first thought was to accept the argument as an (id) and operate on the id object. I can't quite seem to figure out how to do that, however.
Both classes (say apples and oranges) have interface variables:
NSDecimalNumber *count;
I want to do something similar to this:
-(NSDecimalNumber*)addCount:(id)addObject{
return [count decimalNumberByAdding:addObject.count];
}
I can't seem to figure out the syntax to make that happen. Is this the proper approach, or would it be better to subclass (from say a fruit class) and operate on the parent class?
-(NSDecimalNumber*)addCount:(Fruit*)addFruit{
return [count decimalNumberByAdding:addFruit.count];
}
While you can send a message to any object (id) - property accessors require that the compiler be aware of the type you are dealing with - this is because property accessors are syntactic sugar around calling specific getter and setter methods.
You have a few of ways of working around this:
Instead of accessing the count property, call the corresponding [getCount] methods.
If the different classes have different versions of this method, you can use a runtime type check:
Provide a base class for both types so that you can pass in something more specific than (id).
Define and implement a Protocol that both objects implement that defines a count property (or method).
Example of a dynamic type check:
if( [object isKindOfClass:[Apple Class] )
// call one overload of getCount
else if( [object isKindOfClass:[Orange Class] )
// call another overload of getCount
Personally, I favor strong typing in my code because it makes it easier to understand the intent. It also allows the IDE to support your coding effort with intellisense, static analysis, and refactoring features. So, in your case, I would use either #3 or #4 as an approach - depending on whether inheritance is really appropriate for the problem.
You should try not to access instance variables from another class.
In Objective-C it's enough that the two objects respond to the same selector (say count), however that would give you a compiler warning.
There are two ways you can get rid of this warning: either by subclassing from a common Fruit class or by having your two classes conform to a protocol. I'd go with the protocol:
#protocol FruitProtocol
- (NSDecimalNumber *)count;
#end
#interface Orange : NSObject<FruitProtocol>
#end
#interface Apple : NSObject<FruitProtocol>
#end
Then your method can look like this:
-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit {
return [count decimalNumberByAdding:[addFruit count]];
}
Here you are saying that your addCount expects any object that conforms to the FruitProtocol protocol, and hence can respond to the count selector, so the compiler will accept it.
The fact that you are trying to access 'addFruit.count' is the problem. The dot syntax is only for properties declared with #property (or for structs). If you change it to
[addFruit count]
and add
-(NSDecimalNumber*)count
{
return [[count retain] autorelease];
}
to each class, then it would work. However, you will notice you'll get a warning saying 'id' may not respond to the 'count' message, and unless you can be absolutely sure the items sent to this method implement a 'count' method, this is a problematic approach.
I agree with pgb's approach. You should define a protocol, and declare both classes to implement that protocol. This eliminates the problem of not knowing whether the object will respond to 'count' or not, as you now have a 'contract' of sorts.
If you want to keep the dot syntax with a property, you can declare it in the protocol:
#protocol FruitProtocol
#property(readonly) NSDecimalNumber * count;
- (NSDecimalNumber *)count
#end
and then, your function would be:
-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{
return [count decimalNumberByAdding:addObject.count];
}
You're sending the message to count, what is count? id is a pointer to any type of object. If you expect the object to have a count property, then you should only be able to pass in an Array (or some other type restriction).
-(NSDecimalNumber*)addCount:(NSArray*) Object{
return [count decimalNumberByAdding: [Object count]];
}
As I understand it, id does not have any methods or variables associated with it because it is a generic pointer that does not refer to any specific class. This page has some good info on ids if you scroll down a bit.
anObject this will not have a count variable, which is why your first attempt won't work. Creating a base class and using that as a parameter to the method seems like the best idea to me.

Use of pass by reference in Objective-C

Looking at the JSON-Framework source, it makes heavy use of pass by reference in many of the parser method signatures. i.e.
#interface SBJsonParser ()
- (BOOL)scanValue:(NSObject **)o;
- (BOOL)scanRestOfArray:(NSMutableArray **)o;
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o;
#end
This ends up being used something like this:
id o;
[self scanValue:&o];
// Do something with o
- (BOOL)scanValue:(NSObject **)o {
// Cut down for brevity
return [self scanRestOfDictionary:(NSMutableDictionary **)o];
}
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o {
// Cut down for brevity
*o = [NSMutableDictionary dictionaryWithCapacity:7];
[*o setObject:#"value" forKey:#"key"];
return YES;
}
What are the benefits to this approach?
EDIT: I'm asking more from a design point of view. I understand what pass by reference is, I'm just wondering when it's appropriate to use it. The design used in SBJsonParser is similar to the API used in NSScanner:
- (BOOL)scanUpToString:(NSString *)stopString intoString:(NSString **)stringValue;
To me, this implies that the string which was scanned is secondary to needing to know if something was scanned. This is in contrast to the API used by NSString:
+ (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
In that API, the contents of the file is the primary concern, and the NSError reference is used to pass back an error in the event that something goes wrong.
Just after some general thoughts on which API is most appropriate, when.
Those are "output" parameters. They allow the called method to assign a value to your local variable "o". In other words, you're not passing in a reference to an object, but a reference to a local variable.
In your case, the methods return a BOOL to indicate success or failure; therefore, they use output parameters to return other values and objects.
It's really just a style question. It should be consistent across an entire API.
On the one hand, you've got a style where the status code of the call is always returned and output of the call is in the parameter list.
Benefits? You can always check the call result for success. You can easily have multiple return values without changing the style.
Drawbacks? Can't just drop in calls in place of parameters. Harder to chain.
On the other hand, you've got a style where the primary data is returned from the call and any error codes are done through out parameters.
The benefits and drawbacks are essentially inverted.
To be fair, there's a third style: no results are passed out or returned. Instead, exceptions are used.
Benefits? Cleaner looking code.
Drawbacks? Works well for errors, but not so well for status codes that may go along with valid return codes.