假设我有一个结构,我在其中声明:
struct myStruct
{
NSString *aString;
}
上面给出了错误。
但是,我可以通过以下方式修复错误:
struct myStruct
{
__unsafe_unretained NSString *aString;
}
它会使错误无效,但会在运行时崩溃,因为我认为aString会立即释放。
我尝试了__strong
,但不会编译。
有没有其他方法可以在结构中存储对象并正确使用它?
答案 0 :(得分:3)
您可以创建一个新对象,并将其用作指向结构的指针(因为这是Objective C对象)。因此,如果您使用所需的实例变量创建NSObject的子类,则可以将其视为指向结构的指针(一旦初始化它)。即。
myObj = [[myObjClass alloc] init];
myObj->instanceVariable1 = @"myString";
如下面的评论中所述,您需要在界面中声明变量,如下所示:
@interface myObjStruct : NSObject
{
@public
NSString *instanceVariable1;
}
使用NSString,您可以使用CFStringRef,或者将NSString *
转换为CFString并使用CFRetain()
保留它,或使用CFBridgingRetain
立即获得递增的保留计数。您可以使用从CF类型(例如CFArray CFDictionary)桥接的免费类型执行此操作。
struct testStruct {
CFStringRef str;
};
- (void)aMethod
{
NSString *string = @"Hello struct";
struct testStruct test = {
CFBridgingRetain(string),
};
}
您现在拥有该字符串的所有权,并且需要在CFRelease
处调用test.str
以避免内存泄漏。要获得NSString
,请将其投射为NSString *string = (__bridge NSString *)test.str;
。
上面的代码增加了字符串对象的保留计数。可以让这个适用于任何这样的对象:
struct testStruct {
__unsafe_unretained AnyObj *obj;
};
- (void)aMethod
AnyObj *aObj = [[AnyObj alloc] init];
CFBridgingRetain(aObj); \\increment the retain count.
struct testStruct test = {
aObj,
};
aObj = nil;
NSLog(@"%@", aObj);
}
要稍后释放此对象,您需要执行CFRelease((__bridge CFTypeRef)(test.obj));
。请注意,如果删除CFBridgingRetain(aObj);
,此代码可能会崩溃。
您也可以尝试使用id objc_retain(id value);
进行游戏虽然要使用它,但您需要手动包含arc.h标头,请参阅How to import objc_retainAutoreleasedReturnValue?,您可以使用它来增加保留值,就像代码一样以上,但不需要铸造。您还必须使用等效的释放功能。
答案 1 :(得分:2)
__ bridge在Objective-C和Core Foundation之间传输指针,不转让所有权。
__ bridge_retained或CFBridgingRetain将一个Objective-C指针强制转换为Core Foundation指针,并将所有权转移给您。你是 负责调用CFRelease或相关函数放弃 对象的所有权。
__ bridge_transfer或CFBridgingRelease将非Objective-C指针移动到Objective-C,并将所有权转移到ARC。 ARC负责 放弃对象的所有权。
示例(不推荐)
似乎__bridge_retained
,__bridge_transfer
不允许所有权转移到同一类型。所以我使用了额外的__bridge进行类型转换。
我测试过确认的NSString对象是在没有泄漏的情况下发布的。
#define TEST_COUNT 10000
struct myStruct
{
NSString* __unsafe_unretained aString;
};
static struct myStruct* myArray = NULL;
static void allocString()
{
myArray = (struct myStruct*) malloc(sizeof(struct myStruct) * TEST_COUNT);
for (int i=0; i<TEST_COUNT; ++i)
{
NSString* v = [[NSString alloc] initWithFormat:@"%d", i];
myArray[i].aString = (__bridge NSString*)(__bridge_retained void*) v;
}
}
static void freeString()
{
if (myArray)
{
for (int i=0; i<TEST_COUNT; ++i)
{
if (myArray[i].aString)
{
NSString* v = (__bridge_transfer NSString*) (__bridge void*) myArray[i].aString;
v = nil;
}
}
free(myArray);
}
}