如果这是一个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公民会原谅我。为了提高我的互联网业力,也许我会在这个项目发布时将其写成博客文章。
答案 0 :(得分:5)
首先关闭:当你没有NSPointerArray
时,你做有CFMutableArrayRef
,你可以传递任何你想要的保留/释放/描述回调,包括{ {1}}。可能更容易(并且性能是您可以稍后测量的)首先尝试。
按顺序记下你的观点:
您应该按照预期将尺寸定义为NULL
。然后[cacheNumber][days][height]
是类型为cache[cacheNumber]
的二维数组。正如您所说的表现很重要,请注意迭代此野兽的最快方法是:
id *[][]
它应该是for (/* cacheNumber loop */) {
for (/* days loop */) {
for (/* height loop */) {
//...
}
}
}
类型:这是指向指向__strong id ***
的指针的指针,它与(数组)(指向{{1}的指针的数组)相同}))。
id
(!),因为它是上述事物的一系列。你猜错了关于分配数组的问题。如果你正在使用多维数组,你需要这样做(为简洁而省略了一个维度):
id
正确,就是你如何使用这样的指针。
__strong id ****
对象指针,所以你应该是伟大的。也就是说,现在我们的能力已达到极限,所以我可能错了。答案 1 :(得分:3)
回答我自己的问题,因为this web page给了我一些我需要的信息。我也赞成格雷厄姆的答案,因为他非常乐于帮助我理解一些语法。
我缺少的技巧是知道如果我想通过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 *));
}
}
我正在分配一个Item *
s的三维数组,Item
是一个Objective-C类。 (我当然遗漏了此代码段中的错误处理代码。)
一旦我完成了,我可以使用方括号语法引用我的数组:
cacheItems[zoom][day][heightToUse] = item;
我上面链接的网页还描述了执行内存分配的第二种方法,每个维度只使用一次calloc()
调用。我还没有尝试过这种方法,因为我刚才描述的方法目前运作良好。
答案 2 :(得分:0)
我会想到一个不同的实现。除非它是可证明的(即你已经测量并量化了)性能问题,否则尝试将Objective-C对象存储在普通C数组中通常会产生代码味道。
在我看来,你需要一个中间容器对象,我们现在称之为Cache
。每个缓存号都有一个实例,你的对象将保存一个NS(Mutable)数组。 Cache
个对象将具有最大天数和高度的属性。
Cache对象最容易使用其中的对象的NSArray实现,使用简单的算法来模拟两个维度。您的缓存对象将有一个方法-objectAtDay:Height:
来通过其坐标访问该对象。
这样,根本不需要担心内存管理,ARC会为你做这件事。
修改强>
鉴于性能是一个问题,我会使用一维数组并滚动我自己的算法来计算偏移量。实例变量的类型为:
__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示例将适合您。