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

我很抱歉,如果这是一个C-noob问题的一点:我知道我需要swot在我的指针。 不幸的是我已经到了最后期限了,所以没有时间去完成整本书的章节,所以我希望能提供更有针对性的build议。

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

我将存储一个三维C数组:概念上,我的维度是日,高度和cacheNumber。 每个元素将是一个指向一个Objective-C对象的指针,或者是NULL。

caching的数量(即cacheNumber维度的大小)在编译时是已知的,但其他两个是未知的。 另外,数组可能非常大,所以我需要为它dynamic分配内存。

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

我想整个三维数组是一个Objective-C对象的实例variables。

我打算有一个方法是- tableForCacheNumber:(int)num days:(int*)days height:(int*)height 。 该方法应该返回一个二维数组,即一个特定的caching号。 (它也通过引用返回它返回的数组的大小。

我的问题:

  • 我应该用什么顺序放我的尺寸,以便我可以轻松地将指针返回给特定caching号的子数组? (我认为应该是第一,但我不是100%)。

  • 我的方法的返回types应该是什么,以便ARC不会投诉? 我不介意返回的数组是否增加引用计数,只要我知道它在做什么。

  • 我的实例variables保存三维数组是什么types? 我认为它应该只是一个指针,因为这个ivar只是表示指向我的数组中的第一个项目的指针。 正确? 如果是这样,我该如何指定?

  • 当我创build三维数组(对于我的伊娃),我想我会做一些像calloc(X * Y * Z, sizeof(id)) ,并将结果投给我的伊娃的types?

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

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

  • 我是否需要使用objc_returns_inner_pointer标记返回的二维数组?

我再次抱歉,这是一个不好的堆栈溢出问题(太长,部分太多)。 我希望SO的公民会原谅我。 为了提高我的互联网业力,也许我会在这个项目出货时把它写成博客文章。

首先:虽然你没有NSPointerArray ,但你有CFMutableArrayRef ,你可以传递任何你想要的保留/释放/描述的callback,包括NULL 。 这可能会更容易(和性能是你可以测量以后)首先尝试。

顺便说一下你的观点:

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

     for (/* cacheNumber loop */) { for (/* days loop */) { for (/* height loop */) { //... } } } 
  • 它应该是types__strong id *** :这是一个指向指向__strong id ***的指针的指针,这个指针与数组(指向id指针)的数组相同。

  • 你的伊娃需要是__strong id **** (!),因为这是上述的一系列事情。
  • 你猜对分配数组是不正确的。如果你使用的是multidimensional array,你需要这样做(为了简洁,一个维度被忽略了):

     - (__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; } 
  • 正确的,那就是你如何使用这样一个指针。

  • 是的,二维arrays以相同的方式工作, 没有第一维。
  • 我不这么认为,你正在分发__strong对象指针,所以你应该是盛大的。 也就是说,现在我们已经处于这种能力的极限了,所以我很可能是错的。

回答我自己的问题,因为这个网页给了我需要的信息丢失的位。 我也赞成格雷厄姆的回答,因为他对我的头脑中的某些语法非常有帮助。

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

最简单的阅读(尽pipe效率最低)方法就是循环:

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

我正在分配Item * s的三维数组, Item是一个Objective-C类。 (我当然在这个片段中省略了error handling代码。)

一旦我这样做了,我可以使用方括号语法来引用我的数组:

 cacheItems[zoom][day][heightToUse] = item; 

我链接到上面的网页也描述了执行内存分配的第二种方法,每个维度只使用一次calloc()调用。 我还没有尝试过这种方法,因为我刚刚描述的那个方法目前运行得不错。

我会想到一个不同的实现。 除非它是一个可certificate的(即你已经测量和量化的)性能问题,否则试图在普通的C数组中存储Objective-C对象通常是一种代码异味。

在我看来,你需要一个中间的容器对象,我们现在称之为Cache 。 一个实例将存在每个caching号,并且你的对象将拥有一个NS(可变)数组。 Cache对象将具有最大天数和高度的属性。

Cache对象最容易用NSArray中的对象来实现,使用简单的算术来模拟两个维度。 你的caching对象将有一个方法-objectAtDay:Height:通过坐标来访问对象。

这样,完全不需要担心内存pipe理,ARC会为你做。

编辑

鉴于性能是一个问题,我会使用一维数组,并滚动我自己的algorithm来计算偏移量。 你的实例variables的types是:

 __strong id* myArray; 

如果知道所有维的范围(第一个除外),则只能使用C多级下标( array[i][j][k] )。 这是因为实际的偏移量计算为

 (i * (max_j * max_k) + j * max_k + k) * sizeof(element type) 

如果编译器不知道max_j和max_k,就不能这样做。 这正是你所处的情况。

鉴于您必须使用一维数组并手动计算偏移量,Apple示例将为您正常工作。