Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convert std:vector to NSArray

Is there a good way to convert a vector<int32_t> to an NSArray of NSNumber or is looping and adding to an NSMutableArray pretty much the only way?

like image 839
N_A Avatar asked Apr 18 '12 02:04

N_A


2 Answers

If you have a vector of objects, you can do the following:

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

However, if your vector contains primitive types, such as NSInteger, int, float, etc., you would have to manually loop the values in the vector and convert them to a NSNumber first.

like image 82
Richard J. Ross III Avatar answered Oct 10 '22 04:10

Richard J. Ross III


Yes, you can create an NSArray of NSIntegers from a std::vector<NSInteger> by using the following approach:

// 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));
}

However, you will need to be very cautious regarding your use of this collection. Foundation expects the elements to be NSObjects. If you pass it into an external API that expects an array of NSObjects, it will probably cause an error (read: EXC_BAD_ACCESS in objc_msgSend).

Usually, one would convert them to NSNumber. I would use this NSArray of NSIntegers in my program only if another another API needed it (Apple has a few) -- They just don't play very well together.

like image 41
justin Avatar answered Oct 10 '22 05:10

justin