使用ARC将CFErrorRef转换为NSError(或相反)

Tom*_*Tom 12 cocoa objective-c automatic-ref-counting

我曾经像这样将NSError强制转换为CFErrorRef并在SMJobBless中使用它

NSError *error
BOOL removed = SMJobRemove(kSMDomainSystemLaunchd,
                               (CFStringRef) daemonBundleID,
                               auth,
                               true,
                               (CFErrorRef*) &error);
if (!removed) {
        NSLog(@"Failed to remove existing PacketTool");
        [NSApp presentError: error];
    }
Run Code Online (Sandbox Code Playgroud)

由于我在ARC中遇到错误,"ARC禁止使用指向'CFErrorRef'的Obj-C指针的间接指针",我改变并决定做相反的事情

CFErrorRef *cfError = nil;
BOOL blessed = SMJobBless(kSMDomainSystemLaunchd, (__bridge CFStringRef)daemonBundleID,
                          auth,
                          cfError);
if (!blessed) {
    NSError *error = (__bridge NSError *)cfError;
    NSLog(@"Failed to bless PacketTool: %@", error);
    [NSApp presentError: error];
    return FALSE;
}
Run Code Online (Sandbox Code Playgroud)

现在我有一个"不兼容的类型转换'CFErrorRef'到NSError*"与__bridge强制转换

我能做什么?

更新:感谢Greg,正确的代码现在是:

CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(kSMDomainSystemLaunchd,
                          (__bridge CFStringRef) daemonBundleID,
                          auth,
                          &cfError);
if (!blessed) {
    NSError *error = (__bridge NSError *)cfError;
    NSLog(@"Failed to bless PacketTool: %@", error);
    [NSApp presentError: error];
    return FALSE;
}
Run Code Online (Sandbox Code Playgroud)

Gre*_*reg 21

当你声明cfError时你不应该使用指针*,你应该使用:

CFErrorRef cfError = nil;
NSError *error = (__bridge NSError *)cfError;
Run Code Online (Sandbox Code Playgroud)

在另一种方式,它的工作方式如下:

NSError *error = nil;
CFErrorRef ref = (__bridge CFErrorRef) error;
Run Code Online (Sandbox Code Playgroud)

希望这有帮助.


Mec*_*cki 10

在2013年12月7日16:05,汤姆补充说:

更新:感谢Greg,正确的代码现在是:

CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(kSMDomainSystemLaunchd,
                          (__bridge CFStringRef) daemonBundleID,
                          auth,
                          &cfError);
if (!blessed) {
    NSError *error = (__bridge NSError *)cfError;
    NSLog(@"Failed to bless PacketTool: %@", error);
    [NSApp presentError: error];
    return FALSE;
}
Run Code Online (Sandbox Code Playgroud)

我知道这篇文章已经有2年了,但它错了,我不希望其他程序员复制错误的代码.此代码泄漏内存,因为CFError永远不会释放!

CoreFoundation没有自动内存管理,在使用ARC时也没有.ARC仅适用于Obj-C对象.和的CoreFoundation不知道自动释放自动释放池,这样的CoreFoundation对象(CFStringRef,CFNumberRef,CFErrorRef等),你的CoreFoundation功能得到永远不会自动释放.它们要么根本不需要释放,要么由它来释放它们.如果出现错误(CFErrorRef *),则由您来释放它们.

另请参见/sf/answers/603978721/

代码的第一部分是正确的:

CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(
    kSMDomainSystemLaunchd,
    (__bridge CFStringRef)daemonBundleID,
    auth, &cfError
);
Run Code Online (Sandbox Code Playgroud)

但是你需要了解桥梁铸造.最简单的形式或桥梁铸造只是__bridge这个演员告诉ARC"不要做任何事情".如果你这样做

NSError * error = (__bridge NSError *)cfError;
Run Code Online (Sandbox Code Playgroud)

你告诉ARC:"铸cfErrorerror ,但投后不管理错误的记忆,这不关你的事. "

如果你这样做,你仍然有责任释放CFErrorRef!这意味着一旦你完成cfError 使用error("和"因为两者都指向同一个对象,如果它被销毁,两个指针都变得无效),你必须这样做:

CFRelease(cfError);
Run Code Online (Sandbox Code Playgroud)

否则你是在泄漏记忆!

或者,你可以告诉ARC为你管理内存,但是你需要一个不同的演员阵容.如果你这样投

NSError * error = (__bridge_transfer NSError *)cfError;
Run Code Online (Sandbox Code Playgroud)

你告诉ARC:"投cfErrorerror 然后将其由你来管理的记忆error. "

现在您不需要发布任何内容,因为只要error超出范围,ARC就会为您发布.而且因为error并且cfError实际上是同一个对象,释放error也是释放cfError,所以现在你不需要发布任何东西.顾名思义,此转换将对象"转移"到ARC.一旦完成,你就不cfError能再使用,因为你无法确定ARC何时会释放error,并且一旦它确实cfError是一个无效的指针,使用它可能会轻易崩溃你的整个应用程序.

如果你向另一个方向投掷也是如此.如果你这样做

NSError * error = ...;
CFErrorRef cfError = (__bridge CFErrorRef)error;
Run Code Online (Sandbox Code Playgroud)

ARC仍将管理内存error,这是危险的,如上所述,当ARC决定它可以销毁时error,cfError也会变得无效.如果您只cfError在当前范围内使用,这是可以的,但如果您的CFErrorRef需求不管ARC做什么,那么您可以执行此操作:

NSError * error = ...;
CFErrorRef cfError = (__bridge_retained CFErrorRef)error;
Run Code Online (Sandbox Code Playgroud)

这告诉ARC:" 保留error一次,然后施放error,cfError 并且不要平衡这个初始保留. "

因此,即使error超出范围,ARC也不会释放它,因为对象的保留计数器不会变为0,因为该转换,它仍然至少为1.现在由您来处理内存管理,这意味着一旦完成cfError,您必须释放它:

CFRelease(cfError);
Run Code Online (Sandbox Code Playgroud)