【问题标题】:why can't we store C struct directly in NSArray为什么我们不能将 C 结构直接存储在 NSArray 中
【发布时间】:2015-01-26 14:39:43
【问题描述】:

我在尝试将 C 结构存储到 NSArray 时遇到了一个错误(我能够通过转换为 NSData 来解决它,如下面的链接中指定的那样)。但是,我很想知道为什么如果没有使用 NSData 的所有麻烦,它就无法工作。 link to solution I used

请注意:我不想要解决方案,它已经解决了。我只是想通过理解为什么下面的直接方法不起作用来提高我对 Objective-C 基础知识的理解。

我想做的是:一个简单的程序,允许人们添加杂货商品并在添加到购物车后将其标记为已完成

  1. 用 3 个元素定义 C 结构(项目名称、计数和 BOOL 以跟踪它是否已添加到购物车)

  2. 每次创建新项目时,我都会执行以下操作 杂货项目 *secondGroceryItem = malloc(sizeof(groceryItem)) ; secondGroceryItem->itemName="Beer" ; secondGroceryItem->count = 3 ; secondGroceryItem->purchased=NO ;

  3. 然后我将它添加到 NSMutableArray 中,使用 [myGroceryList addObject:(__bridge id)(secondGroceryItem)]

myGroceryList 在前面定义为 NSMutableArray *myGroceryList = [NSMutableArray 数组] ;

这不起作用。在存储到 NSMutableArray 之前,我必须转换为 NSData。为什么我不能直接在 NSMutableArray 中存储指向我的 C 结构的指针?

【问题讨论】:

  • C 结构不是 NSObject。只有 NSObject pointers 可以存储在 NSArrays 中。您可以(在某些情况下)使用 NSValue 作为 C 结构的“容器”。可能比一些 NSData kluge 更好,但仍然有点不稳定。 (而且几乎没有什么情况下你需要使用 C 结构,除非你正在做一些非常奇怪的事情。)
  • 我不确定这个问题是否真的可以回答。简单的答案是,正如 Hot Licks 所说,“因为NSArray 只能存储对象”。更复杂的答案意味着要回到 NeXT 工程师 20 多年前做出的决定。无论如何,推荐的解决方案是将您的结构转换为简单的数据类,将字段变成属性。
  • 我们也不能在NSArray 中放入整数、浮点数、字符等。 NSArray 是一种特殊类型的 Objective-C 对象数组。

标签: objective-c c


【解决方案1】:

需要注意的是,我们不能将 C-structs 放入NSArray 并不是因为结构体有什么特别之处。相反,我们应该将NSArray 视为一种特殊类型的数组。

我们可以在 Objective-C 中将结构放入数组中。我们知道这一点是因为 C 程序员将结构放入数组中。

NSArray(和NSMutableArray 和所有其他NS 集合对象)是一个特殊的类,旨在实现专门用于Objective-C 对象的数组数据结构。事实上NSArray 只允许Objective-C 对象允许NSArray 做类似makeObjectsPerformSelector: 的事情。我们正在向数组中的所有内容发送一条 Objective-C 消息。如果我们允许非 Objective-C 对象进入数组,我们就不允许这样做。

不仅仅是structs 不允许进入NSArrayNSArray 中不允许所有原始数据类型。这甚至包括NSIntegerCGFloat,因为请记住,这些是类型定义的原语——而不是对象。

需要注意的是,NSArray 并不是我们在 Objective-C 中唯一可用的类似数组的数据结构。请记住,Objective-C 是 C 的严格超集。正如我已经提到的,C 程序员已经将结构放入数组中。

我们总是可以使用 C 风格的数组。事实上,虽然很少这样做(因为 Objective-C 数组的强大功能),但我们甚至可以创建一个 C 风格的 Objective-C 对象数组。

考虑:

NSString *stringArray[3];
stringArray[0] = @"foo";
stringArray[1] = @"bar";
stringArray[2] = @"baz";

for (int i = 0; i < 3; ++i) {
    NSLog(@"%@", stringArray[i]);
}

这完全按照您在 Objective-C 中的期望进行编译、运行和执行。因此,我们可以用 struct 做同样的事情:

typedef struct Foo {
    int x;
    int y;
} Foo;

Foo fooArray[3];
fooArray[0] = (Foo){.x = 1, .y = 2};
fooArray[1] = (Foo){.x = 3, .y = 4};
fooArray[2] = (Foo){.x = 5, .y = 6};

for (int i = 0; i < 3; ++i) {
    NSLog(@"Foo(x: %i, y: %i)", fooArray[i].x, fooArray[i].y);
}

同样,这是完全有效的 Objective-C 代码。

您必须问自己的问题:拥有一个结构体并处理一个 C 样式的数组更好,还是我的结构体作为一个对象更好,我可以放入 NSArray 中?我不会使用 struct,我将其转换为 NSData 并返回只是为了将其放入 NSArray...这似乎是一团糟。

【讨论】:

    【解决方案2】:

    NSArray 或 NSMutableArray 由对象组成。 C 数据类型不是对象。所以你不能将它们直接存储在 NSArray 中。

    我假设你知道如何创建一个对象。在此对象中包含 C 数据类型的变量。

    一旦你有了,将该对象添加到 NSArray:

    NSMutableArray *yourArray = [[NSMutableArray alloc] init];
    
    YourObject *object1 = [[YourObject alloc] init];
    [yourArray addObject: object1];
    

    【讨论】:

    • 谢谢,为每件小事创建一个类似乎有点过头了。我想我必须将其与必须通过 NSData kludge 的开销进行比较,或者根据具体情况决定是否需要 NSArray 给我的任何特殊东西(即使用常规数组代替)。
    • 这也适用于 NSDATA。
    猜你喜欢
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多