Objective-C ARC和传递C对象数组

Amy*_*all 8 objective-c ios automatic-ref-counting

如果这是一个C-noob问题,我很抱歉:我知道我需要注意我的指针.不幸的是我在截止日期,所以没有时间完成整本书的章节,所以我希望有更多有针对性的建议.

我想在C数组中存储一些Objective-C对象.我正在使用ARC.如果我在Mac上,我可以使用NSPointerArray,但我在iOS上并且不可用.

我将存储一个三维C数组:从概念上讲,我的维度是day,height和cacheNumber.每个元素都是指向Objective-C对象的指针,或者是NULL.

高速缓存的数量(即cacheNumber维度的大小)在编译时是已知的,但其他两个是未知的.此外,阵列可能非常大,所以我需要为它动态分配内存.

关于所有权语义,我需要对对象的强引用.

我希望整个三维数组成为Objective-C对象的实例变量.

我计划有一个方法- tableForCacheNumber:(int)num days:(int*)days height:(int*)height.该方法应该返回一个二维数组,即一个特定的缓存号.(它还通过引用传回它返回的数组的大小.)

我的问题:

  • 我应该将我的维度放在什么顺序,以便我可以轻松地返回指向一个特定缓存号的子数组的指针?(我认为它应该是第一个,但我不是100%.)

  • 我的方法的返回类型应该是什么,以便ARC不抱怨?我不介意返回的数组是否有增加的引用计数,只要我知道它正在做什么.

  • 我的实例变量应该包含三维数组的类型是什么类型?我认为它应该只是一个指针,因为ivar只表示指向我数组中第一个项目的指针.正确?如果是这样,我该如何指定?

  • 当我创建三维数组(对于我的ivar)时,我想我会做类似的事情calloc(X * Y * Z, sizeof(id)),并将结果转换为我的ivar类型?

  • 当从ivar中的三维数组访问项目时,我相信我每次都必须取消引用指针,例如(*myArray)[4][7][2].正确?

  • 我是否会同样访问从方法返回的二维数组?

  • 我需要标记返回的二维数组objc_returns_inner_pointer吗?

我再次感到遗憾,这是一个糟糕的Stack Overflow问题(它太长而且部分太多).我希望SO公民会原谅我.为了提高我的互联网业力,也许我会在这个项目发布时将其写成博客文章.

小智 5

第一关:当你没有NSPointerArray,你必须CFMutableArrayRef和你可以通过任何你想要的回调保留/释放/描述,包括NULL.可能更容易(并且性能是您可以稍后测量的)首先尝试.

按顺序分数:

  • 您应该[cacheNumber][days][height]按照预期定义尺寸.然后cache[cacheNumber]是一个二维数组类型id *[][].正如您所说,性能很重要,请注意迭代这个野兽的最快方法是:

    for (/* cacheNumber loop */) {
     for (/* days loop */) {
      for (/* height loop */) {
       //...
      }
     }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 它应该是类型__strong id ***:这是指向指向指针的指针id,它与(数组的指针id)数组相同.

  • 你的ivar需要__strong id ****(!),因为它是上面的一系列东西.
  • 你猜错了关于分配数组的问题.如果你使用的是多维数组,你需要这样做(为了简洁,省略了一个维度):

    - (__strong id * * *)someArray {
        __strong id * * *cache = (__strong id * * *)malloc(x*y*sizeof(void *));
        id hello = @"Hello";
    
        cache[0] = (__strong id * *)malloc(sizeof(void *)); //same for cache[1..x-1]
        cache[0][0] = &hello; // for all cache[x][y]
    
        return (__strong id * * *)cache;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 正确的,就是你如何使用这样的指针.

  • 是的,二维阵列以同样的方式工作,没有第一个维度.
  • 我不这么认为,你是在分发__strong对象指针,所以你应该是伟大的.也就是说,我现在处于这种能力的极限,所以我可能错了.


Amy*_*all 3

回答我自己的问题,因为这个网页为我提供了我需要的缺失信息。我也赞成格雷厄姆的回答,因为他对我理解一些语法很有帮助。

我缺少的技巧是知道如果我想通过array[1][5][2]语法引用数组中的项目,并且我在编译时不知道数组的大小,我不能只calloc()使用单个数据块。

最容易阅读(尽管效率最低)的方法就是使用循环:

__strong Item ****cacheItems;

cacheItems = (__strong Item ****)calloc(kMaxZooms, sizeof(Item ***));

for (int k = 0; k < kMaxZooms; k++) 
{
    cacheItems[k] = (__strong Item ***)calloc((size_t)daysOnTimeline, sizeof(Item **));

    for (int j = 0; j < daysOnTimeline; j++) 
    {
        cacheItems[k][j] = (__strong Item **)calloc((size_t)kMaxHeight, sizeof(Item *));
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在分配一个 s 的三维数组Item *Item作为 Objective-C 类。(当然,我在这段代码中省略了错误处理代码。)

完成此操作后,我可以使用方括号语法引用我的数组:

cacheItems[zoom][day][heightToUse] = item;
Run Code Online (Sandbox Code Playgroud)

我上面链接到的网页还描述了执行内存分配的第二种方法,该方法仅对calloc()每个维度使用一次调用。我还没有尝试过这种方法,因为我刚才描述的方法目前效果很好。