将std::vector转换为NSArray

19
有没有好的方法将vector<int32_t>转换为NSNumberNSArray,或者循环并添加到NSMutableArray是唯一的方法?

NSArray 不能包含原始类型 NSInteger 的元素。 - Richard J. Ross III
1
@RichardJ.RossIII实际上,它确实可以。我在我的答案中已经演示了这一点。 - justin
2个回答

20

如果你有一个对象向量,你可以执行以下操作:

NSArray *myArray = [NSArray arrayWithObjects:&vector[0] count:vector.size()];

然而,如果您的向量包含原始类型,例如 NSInteger, int, float 等,您将不得不手动循环向量中的值并首先将它们转换为 NSNumber


在处理向量对象的生命周期时,务必非常小心! - Richard
1
这回答了我的问题。我确实有一个 vector<int32_t>,所以不幸的是我必须无论如何循环遍历所有的值。 - N_A
2
这对我不起作用。我得到了“无法使用类型'const __unsafe_unretained id *'的参数初始化rvalue of type...” - Greg M. Krsak
1
@Greg 第二种类型是什么?这是在ARC出现之前完成的,所以你可能需要转换指针。 - Richard J. Ross III
抱歉,我匆忙之中误解了你的回答。你是对的——它有效。我认为更清晰的表述应该是“Objective-C对象的向量”。如果进行编辑,我愿意改变我的投票。 - Greg M. Krsak
@Greg,我目前看不到更新此答案并将其推到前面的理由,而且您的评论确实是有效的,所以我现在会将其保持原样。反正那两个声望点数也没什么意义。 - Richard J. Ross III

5

是的,你可以使用以下方法从 std::vector<NSInteger> 创建一个 NSArray

// thrown together as a quick demo. this could be improved.
NSArray * NSIntegerVectorToNSArrayOfNSIntegers(const std::vector<NSInteger>& vec) {

  struct MONCallback {
    static const void* retain(CFAllocatorRef allocator, const void* value) {
      /* nothing to do */
      return value;
    }

    static void release(CFAllocatorRef allocator, const void* value) {
      /* nothing to do */
    }

    static CFStringRef copyDescription(const void* value) {
      const NSInteger i(*(NSInteger*)&value);
      return CFStringCreateWithFormat(0, 0, CFSTR("MON - %d"), i);
    }

    static Boolean equal(const void* value1, const void* value2) {
      const NSInteger a(*(NSInteger*)&value1);
      const NSInteger b(*(NSInteger*)&value2);
      return a == b;
    }
  };

  const CFArrayCallBacks callbacks = {
    .version = 0,
    .retain = MONCallback::retain,
    .release = MONCallback::release,
    .copyDescription = MONCallback::copyDescription,
    .equal = MONCallback::equal
  };

  const void** p((const void**)&vec.front());
  NSArray * result((NSArray*)CFArrayCreate(0, p, vec.size(), &callbacks));
  return [result autorelease];  
}

void vec_demo() {
  static_assert(sizeof(NSInteger) == sizeof(NSInteger*), "you can only use pointer-sized values in a CFArray");

  std::vector<NSInteger> vec;
  for (NSInteger i(0); i < 117; ++i) {
    vec.push_back(i);
  }
  CFShow(NSIntegerVectorToNSArrayOfNSIntegers(vec));
}

然而,你需要非常谨慎地使用这个集合。Foundation希望这些元素是NSObject。如果你将它传递到期望NSObject数组的外部API中,它很可能会引发错误(即:objc_msgSend中的EXC_BAD_ACCESS)。
通常,人们会将它们转换为NSNumber。我只会在另一个API需要它时才在我的程序中使用这个NSArrayNSInteger - Apple有一些这样的API - 它们只是不能很好地配合使用。

3
我实际上是指NSNumber,但是因为你的精彩回答,我给了你一个赞! - N_A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接