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示例将为您正常工作。