我曾经像这样将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];
}
由于我在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;
}
现在我有一个“不兼容的类型''CFErrorRef'到NSError *”,带有__bridge cast
我该怎么办?
更新:感谢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;
}
答案 0 :(得分:20)
当你声明cfError时你不应该使用指针*,你应该使用:
CFErrorRef cfError = nil;
NSError *error = (__bridge NSError *)cfError;
另一方面,它的工作原理如下:
NSError *error = nil;
CFErrorRef ref = (__bridge CFErrorRef) error;
希望得到这个帮助。
答案 1 :(得分: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; }
我知道这篇文章已经有2年了,但它错了,我不希望其他程序员复制错误的代码。 此代码泄漏内存,因为CFError永远不会被释放!
CoreFoundation没有自动内存管理,使用ARC时也没有。 ARC仅适用于Obj-C对象。并且CoreFoundation不知道自动释放或自动释放池,因此CoreFoundation对象(CFStringRef
,CFNumberRef
,CFErrorRef
等)你从CoreFoundation函数获得永远不会自动释放。它们要么根本不需要释放,要么由它来释放它们。如果出现错误(CFErrorRef *
),则由您自行决定。
另见https://stackoverflow.com/a/8628267/15809
代码的第一部分是正确的:
CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(
kSMDomainSystemLaunchd,
(__bridge CFStringRef)daemonBundleID,
auth, &cfError
);
但是你需要了解桥梁铸造。最简单的形式或桥接铸造只是__bridge
,这个演员告诉ARC“不要做任何事”。如果你这样做
NSError * error = (__bridge NSError *)cfError;
你告诉ARC:“将cfError
投放到error
,但是在投放后不管理错误的记忆,这不关你的事。”
如果你这样做,你仍然有责任释放CFErrorRef
!这意味着一旦你完成cfError
和与error
(“和”因为两者都指向同一个对象,如果它被销毁,两个指针都变得无效),你必须这样做:
CFRelease(cfError);
否则你是在泄漏记忆!
或者你可以告诉ARC为你管理内存,但是你需要一个不同的演员阵容。如果你像那样投射
NSError * error = (__bridge_transfer NSError *)cfError;
你告诉ARC:“将cfError
投射到error
,然后由你来管理error
的记忆。”
现在您不需要发布任何内容,因为只要error
超出范围,ARC就会为您发布。由于error
和cfError
实际上是同一个对象,因此发布error
也会释放cfError
,所以现在您不需要发布任何内容。顾名思义,此转换将对象“转移”到ARC。完成后,您不能再使用cfError
了,因为您无法确定ARC何时会释放error
,并且一旦确定,cfError
就是无效的指针使用它可以轻松崩溃整个应用程序。
如果你向另一个方向投掷也是如此。如果你这样做
NSError * error = ...;
CFErrorRef cfError = (__bridge CFErrorRef)error;
ARC仍将管理error
的内存,这很危险,如上所述,当ARC决定它可以销毁error
时,cfError
也将无效。如果你只在当前范围内使用cfError
,这是没关系的,但是如果你的CFErrorRef
需要生存而不管ARC做什么,那么你就做了这个演员:
NSError * error = ...;
CFErrorRef cfError = (__bridge_retained CFErrorRef)error;
这告诉ARC:“保留error
一次,然后将error
投射到cfError
,并且不要平衡此初始保留。< /强>“
因此,即使error
超出范围,ARC也不会释放它,因为对象的保留计数器不会变为0,因为该转换,它仍然至少为1。现在由您来处理内存管理,这意味着一旦完成cfError
,您必须释放它:
CFRelease(cfError);