我这样调用我的实用方法:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"dd.MM.yy HH:mm"];
NSString *dateString = [dateFormat stringFromDate:[NSDate date]];
return [[Environment sharedInstance].versionLabelFormat replaceTokensWithStrings:
@"VERSION", APP_VERSION,
@"BUILD", APP_BULD_NUMBER,
@"DATETIME" , dateString,
nil ];
这是 NSString
类别法
-(NSString *)replaceTokensWithStrings:(NSString *)firstKey, ... NS_REQUIRES_NIL_TERMINATION{
NSString *result = self;
va_list _arguments;
va_start(_arguments, firstKey);
for (NSString *key = firstKey; key != nil; key = va_arg(_arguments, NSString*)) {
// The value has to be copied to prevent crashes
NSString *value = [(NSString *)(va_arg(_arguments, NSString*))copy];
if(!value){
// Every key has to have a value pair otherwise the replacement is invalid and nil is returned
NSLog(@"Premature occurence of nil. Each token must be accompanied by a value: %@", result);
return nil;
}
result = [result replaceToken:key withString:value];
}
va_end(_arguments);
// Check if there are any tokens which were not yet replaced (for example if one value was nil)
if([result rangeOfString:@"{"].location == NSNotFound){
return result;
} else {
NSLog(@"Failed to replace tokens failed string still contains tokens: %@", result);
return nil;
}
}
否 在下一行我必须添加 copy
声明否则会有一个带有dateString
的僵尸:
NSString *value = [(NSString *)(va_arg(_arguments, NSString*))copy];
更具体地说,僵尸报告告诉我的是:
1 Malloc NSDateFormatter stringForObjectValue:
Autorelease NSDateFormatter stringForObjectValue:
2 CFRetain MyClass versionString:
3 CFRetain replaceToken:withString:
2 CFRelease replaceToken:withString:
1 CFRelease replaceTokensWithStrings: ( One release too much!)
0 CFRelease MyClass versionString:
-1 Zombie GSEventRunModal
尽管 copy
语句似乎解决了问题我想了解代码不符合 ARC 的原因,以便 BAD_ACCESS
没有 copy
就会发生对于值字符串。
最佳答案
正如其他人所说,问题在于您从可能与 ARC 不兼容的可变参数列表中检索对象的方式。
va_arg
有一种有趣的方式来返回 ARC 可能不知道的特定类型的值。我不确定这是 clang 中的错误还是 ARC 的预期行为。我会澄清这个问题并相应地更新帖子。
作为解决方法,只需在参数处理中使用 void 指针并以 ARC 安全方式将它们正确转换为对象即可避免此问题:
for (NSString *key = firstKey; key != nil; key = (__bridge NSString *)va_arg(_arguments, void *)) {
NSString *value = (__bridge NSString *)va_arg(_arguments, void *);
NSAssert(value != NULL, @"Premature occurence of nil.");
result = [result stringByReplacingToken:key
withString:value];
}
编辑:__bridge 转换告诉 ARC 不要对所有权做任何事情。它只是期望对象是活着的,不会转移或放弃所有权。然而,key
和 value
变量在使用时保持对对象的强引用。
第二次编辑:似乎 clang/ARC 应该知道 va_arg 中的类型并发出警告或做正确的事情(see this, for example)。
我尝试重现您的问题,但没有成功。一切都适合我:
$ clang --version
> Apple clang version 4.0 (tags/Apple/clang-421.10.48) (based on LLVM 3.1svn)
您使用哪个 Xcode 版本?
关于iphone - ARC `BAD_ACCESS` 使用 NSString 的类别方法时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11576293/