简体   繁体   English

ARC和varargs导致BAD_ACCESS

[英]ARC and varargs causes BAD_ACCESS

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. 我正在查看一个可变参数列表,当我到达列表中的最后一个对象时,总是会收到BAD_ACCESS错误。 I strongly assume that it is an ARC related issue. 我强烈认为这是与ARC相关的问题。

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. 我必须以某种方式告诉编译器保留va_arg返回的结果,但我似乎无法弄清楚在何处以及如何应用此范例。

Update 1: This is how I call my method: 更新1:这就是我调用方法的方式:

[@"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. 更新2:我更新了我的问题,并添加了一个错误,以表明我实际上做错了什么。 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. 我已经更新了我的问题,实际的问题是我没有传递一个NSString列表,而是5个NSString, 最后一个是普通的C字符串。

The last C string caused the BAD_ACCESS : 最后一个C字符串导致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. 每当C中有一个可变参数列表时,您都需要以某种方式指定列表中的项目数或标识最后一个项目-语言不会为您完成此操作。 This can be via a format statement -- number of args matches number of format items -- or some other scheme. 这可以通过format语句-args数量与format项的数量匹配-或其他方案。 The default scheme is to end the parameter list in the calling statement with nil or NULL . 默认方案是使用nilNULL结束调用语句中的参数列表。

If you look at the definitions of things like NSArray arrayWithObjects , the list must always be terminated with nil . 如果您查看诸如NSArray arrayWithObjects类的定义,则列表必须始终以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: 我也在使用ARC ,正在使用以下模式,它对我来说很好用,我从未遇到过任何问题,它可能会对您有所帮助:

- (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 我今天也遇到了同样的问题,可以从技术上告诉您与ARC或保留无关,但是您的方法声明/原型应该是

-(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) 这样,您告诉Xcode和C预处理程序使用MACRO,并总是要求以'nil'结尾,因此它将阻止va_arg()访问错误的位置(BAD_ACCESS)

It has nothing to do with ARC. 它与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. va_arg不会检查它是否到达列表的末尾,因此将返回一个指向列表之后的内存块的指针,该指针可以是任何东西。 Hence the EXC_BAD_ACCESS. 因此,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. 然后在while循环中使用numStrings

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. 如果期望va_arg返回的ID类型(在此示例中为NSString *),并且它返回nil值,则会发生崩溃。 This is because arc is trying to retain the nil that is returned. 这是因为arc试图保留返回的nil。

to avoid this add __unsafe_unretained to the variable you are assigning to. 为了避免这种情况,请在要分配的变量中添加__unsafe_unretained。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM