__unsafe_unretained in struct

时间:2014-07-11 18:23:22

标签: objective-c c

假设我有一个结构,我在其中声明:

struct myStruct
{
    NSString *aString;
}

上面给出了错误。

但是,我可以通过以下方式修复错误:

struct myStruct
{
    __unsafe_unretained NSString *aString;
}

它会使错误无效,但会在运行时崩溃,因为我认为aString会立即释放。

我尝试了__strong,但不会编译。

有没有其他方法可以在结构中存储对象并正确使用它?

2 个答案:

答案 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)

Toll-Free Bridged Types

  
      
  • __ 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);
    }
}