开发者

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开发者_Python百科 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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜