Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 989
alex Avatar asked Jul 26 '10 01:07

alex


People also ask

Is Objective C pass by value or reference?

Objective-C Language Methods Pass by value parameter passing So actual parameter value will not change after returning from called function.


3 Answers

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); 
like image 183
bbum Avatar answered Sep 28 '22 01:09

bbum


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.)

like image 40
andyvn22 Avatar answered Sep 28 '22 02:09

andyvn22


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

like image 45
bhause Avatar answered Sep 28 '22 02:09

bhause