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.
Related
Apologies for such a newbie question.
I have written a class method that takes three strings and returns a substring.
I have written conditional statements that only allow the substring to returned if certain criteria are met. However I am unsure what I need to return if the substring cannot be extracted. At the moment I have the method returning a default 'error' string, but I have the feeling that this may not be best practice.
Here is my method:
+(NSString *)ExtractSubstringFrom:(NSString *)sourceString
Between:(NSString *)firstString And:(NSString *)secondString {
NSRange stringRangeOne = [sourceString rangeOfString:secondString];
NSString *resultString;
if (stringRangeOne.location != NSNotFound) {
resultString = [sourceString substringToIndex:stringRangeOne.location];
}
NSRange stringRangeTwo = [sourceString rangeOfString:firstString];
if (stringRangeTwo.location !=NSNotFound) {
resultString = [resultString substringFromIndex:stringRangeTwo.location+stringRangeTwo.length];
return resultString;
}
else return #"Error!";
//To do... improve error checking
}
How can I make this method more error friendly?
There are several ways of handling errors of this kind in Objective C:
Returning the default value - typically, the default value is nil. Since performing operations on nil objects is allowed in Objective C, this is relatively safe.
Producing NSError objects - this is more typical of errors that can be addressed by end users, such as connection and configuration problems. The unfortunate side effect of this kind of API is the need to set up and pass an extra parameter.
Using an assertion - this is a good way of handling "programming errors", i.e. when your program's arguments are out of their specified ranges.
Throwing an exception - this option is available in the language, but Apple strongly discourages against using it. I mentioned it here for completeness, even though I never use this option myself.
The actual best practice here would be to NOT do this inside the class method, but instead implement Key Value Validation on the thing that will be accepting the value, and calling the validation method before it is set. So you would remove this validation/mutation logic from this method and instead put it inside your validation method, and in the controller the value is being modified called the validation method before setting the value. This gives your validation logic the opportunity to modify the value (i.e. to a default) or return an error if the input value can't be coerced into something useable.
For more general information on error handling in Objective-C, see Programming With Objective-C: Dealing with Errors and Error Handling Programming Guide
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.
NSError objects are frequently used like this (taken from this previous question):
- (id)doStuff:(id)withAnotherObjc error:(NSError **)error;
I want to achieve something similar with BOOL indirection:
- (id)doStuff:(id)withAnotherObjc andExtraBoolResult:(BOOL **)extraBool;
But I can't figure out how to get this working correctly.
For the given method specification involving NSError, the proper implementation would involve something like (again from the previous question):
*error = [NSError errorWithDomain:...];
With similar logic, it seems like this should work with BOOL indirection:
*extraBool = &YES; // ERROR! Address expression must be an lvalue or a function designator
Why doesn't this work and what is the proper way to implement this?
Keep in mind that with objects, you're working with a pointer (e.g., NSError*), so using this method, you wind up with a pointer to a pointer (e.g., NSError**). When working with a BOOL, though, you should use a pointer to a BOOL: that is, only one level of indirection, not two. Therefore, you mean:
- (id)doStuff:(id)withAnotherObjc andExtraBoolResult:(BOOL *)extraBool;
and subsequently:
*extraBool = YES;
In the book Clean Code the author recommends breaking large methods into small functions that do one specific thing. In languages like Java this translates to pretty, readable code.
public static String renderPage(PageData pageData)
{
includeHeader(pageData);
includeContent(pageData);
includeFooter(pageData);
return pageData.getHtml();
}
However in Objective-C as far as I know the only way to implement functions like this are to create private methods and call them by messaging self
- (NSString *)renderPageWithData:(PageData *)pageData {
[self includeHeader:pageData];
[self includeContent:pageData];
[self includeFooter:pageData];
return [pageData HTML];
}
I feel like messaging self implies some sort of operation that the object is doing to itself. C functions aren't really an option because the don't fall under the scope of the class. Meaning I can't access any of the instance variables or the class object with out doing extra legwork, and adding complexity.
I'm looking for a good way to create clean code with regard to functions or methods in Objective-C
There is no difference between the two code blocks you posted. The only reason it looks different is that in java, the this. is implicit when you make a function call without specifying an object.
Edit: I just noticed that your java method is static. If you want them to remain static methods, you would then just use [MyCLass ...] instead of [self ...].
I see your point about the function calls: self and include in the same "sentence" make it look as though things are being included in the class itself. I would solve that with more explicit method names:
- (NSString *)renderPageWithData:(PageData *)pageData {
[self renderHeaderWithData:pageData];
[self renderContentWithData:pageData];
[self renderFooterWithData:pageData];
return [pageData HTML];
}
I'm not sure what you mean by "they don't fall under the scope of the class"; local C functions that don't need to get at object member properties seem like a fine solution here to me. But I don't think there's anything particularly wrong with private methods, either.
Personally, I would use C functions here.
Edit: if your refactored functions need access to object state—implying that you'd be passing self as an argument—then I'd go ahead and leave it as a method. There's very little difference between
[self includeHeader:pageData];
and
includeHeader(self, pageData);
Even if you find both of these options slightly distasteful from an aesthetic position, they're both huge improvements for readability and its close cousin, maintainability, compared to having long functions that do several different pieces of work.
You should be using class methods when they share some properties.
Without to see all the code, and without to know how the code is used, I could suggest to create a pageData property, and change the other functions so they don't need to pass the parameter between them.
If it is not possible, or the parameter pageData is very temporary, then plain functions could be better.
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?