I am going through a list of varargs and when I reach the last object in the list I always get a BAD_ACCESS
error. I strongly assume that it is an ARC related issue.
This is what I do:
-(NSString *)replaceTokensWithStrings:(NSString *)firstKey, ... {
va_list _arguments;
va_start(_arguments, firstKey);
for (NSString *_currentArgument = firstKey; _currentArgument != nil; _currentArgument = va_arg(_arguments, NSString*)) {
NSLog(@"%@", _currentArgument);
}
va_end(_arguments);
return nil;
}
I have to somehow tell the compiler to retain the result returned by va_arg
but I can't seem to figure out where and how to apply this paradigm.
Update 1: This is how I call my method:
[@"Hello <firstname> <lastname>" replaceTokensWithStrings:
@"firstname", @"Peter",
@"lastname", "Smith",
nil];
Update 2: I updated my question and added an error I made to reveal what I've actually done wrong. See my answer below.
I was thoroughly on the wrong path. The problem was not the function at all but how I called the function (The other participants could not have known this because I did not do the error in my example in my question).
I have updated my question and the actual problem was that I did not pass a list of NSStrings but 5 NSStrings and the last one was an normal C String.
The last C string caused the BAD_ACCESS
:
BAD:
"Smith"
GOOD:
@"Smith"
Now I am embarassed :-)
Whenever you have a varargs list in C you need to somehow specify the number of items in the list or identify the last item -- the language does not do it for you. This can be via a format statement -- number of args matches number of format items -- or some other scheme. The default scheme is to end the parameter list in the calling statement with nil
or NULL
.
If you look at the definitions of things like NSArray arrayWithObjects
, the list must always be terminated with nil
.
I'm working with the ARC
as well, I'm using the following pattern and it works fine for me, I've never experienced any issue with it, it might help you:
- (void)workingWithDictionaries:(NSDictionary *)dictionary, ... {
va_list _arguments;
va_start(_arguments, dictionary);
for (NSDictionary *_currentArgument = dictionary; _currentArgument != nil; _currentArgument = va_arg(_arguments, NSDictionary*)) {
NSLog(@"%@", _currentArgument);
}
va_end(_arguments);
}
I faced same issue today, and can tell you technically it has nothing to do with ARC or retain, but your method declaration/prototype should be
-(NSString *)replaceTokensWithStrings:(NSString *)firstKey, ...
NS_REQUIRES_NIL_TERMINATION;
That way you tell Xcode and C preprocessor to use the MACRO and asks always to finish with 'nil' so it stops va_arg() from accessing a wrong position (BAD_ACCESS)
It has nothing to do with ARC. va_arg does not check that it arrived at the end of the list, so will return a pointer to the memory block after the list, which can be anything. Hence the EXC_BAD_ACCESS. Generally you give the amount of arguments as extra parameter, something like:
-(void *)replaceTokensWithNumberOfStrings:(int)numStrings strings:(NSString *)str1, ... {
Then use the numStrings
in your while
loop.
If you are expecting an id type from a va_arg return (in this example, NSString*) and it returns a nil value, a crash will occur. This is because arc is trying to retain the nil that is returned.
to avoid this add __unsafe_unretained to the variable you are assigning to.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.