1

I have a C type pointer variable:

a_c_type *cTypePointer = [self getCTypeValue];

How can I convert cTypePointer to NSObject type & vise versa?

Should I use NSValue? What is the proper way to do so with NSValue?

Avi
  • 7,469
  • 2
  • 21
  • 22
Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • What are you trying to do with the pointer? You can't just convert something to be an NSObject reference. – Avi Aug 11 '16 at 07:45
  • @Avi, why can not? I found NSValue is the thing I need, but don't know the proper way of using it in my case, so I ask here. – Leem.fin Aug 11 '16 at 07:50
  • Because you are using the wrong terminology. `NSValue` stores a value. It doesn't convert from one type to another. – Avi Aug 11 '16 at 07:52
  • NSValue store a value indeed, it can be anything C type as long as it knows the address of the 1st bit of the information and the length it as to read. Pointer and type. that all NSValue need. The terminology "wrap" would have been better than "convert" of course, but, still – Florian Burel Aug 11 '16 at 07:58
  • I will try to use terminology more accurate in future, but I think people understand what I am trying to ask. – Leem.fin Aug 11 '16 at 08:01

2 Answers2

1

You can indeed use a NSValue.

a_c_type *cTypePointer = [self getCTypeValue];
NSValue * storableunit = [NSValue valueWithBytes:cTypePointer objCType:@encode(a_c_type)];

note that the 1st parameter is a pointer (void*). the object will contain the pointed value.

to get back to C:

a_c_type element;
[value getValue:&element];

Note that you would get the actual value, not the pointer. But then, you can just

 a_c_type *cTypePointer = &element

Test it :

- (void) testCVal
{
    double save = 5.2;
    NSValue * storageObjC = [NSValue valueWithBytes:&save objCType:@encode(double)];


    double restore;
    [storageObjC getValue:&restore];

    XCTAssert(restore == save, @"restore should be equal to the saved value");

}

test with ptr :

typedef struct
{
    NSInteger day;
    NSInteger month;
    NSInteger year;
} CDate;

- (void) testCVal
{
    CDate save = (CDate){8, 10, 2016};
    CDate* savePtr = &save;

    NSValue * storageObjC = [NSValue valueWithBytes:savePtr objCType:@encode(CDate)];


    CDate restore;
    [storageObjC getValue:&restore];
    CDate* restorePtr = &restore;

    XCTAssert(restorePtr->day == savePtr->day && restorePtr->month == savePtr->month && restorePtr->year == savePtr->year, @"restore should be equal to the saved value");

}
Florian Burel
  • 3,408
  • 1
  • 19
  • 20
  • Thanks, I will try it soon & get back to you. – Leem.fin Aug 11 '16 at 07:50
  • Hmm...it doesn't work for me... could you please make a test on a c type pointer than primitive type 'double'? – Leem.fin Aug 11 '16 at 08:05
  • I see, take @Florian Burel's answer as reference, I need the 'restore' variable, then assign its address to the restorePtr, I missed this step. Now it works for me as well! – Leem.fin Aug 11 '16 at 08:26
1

You simply use the method valueWithPointer: to wrap a pointer value as an NSValue object, and pointerValue to extract the pointer value.

These are just like valueWithInt:/intValue et al - they wrap the primitive value. You are not wrapping what the pointer points at. Therefore it is important that you ensure that when extract the pointer that whatever it pointed at is still around, or else the pointer value will be invalid.

Finally you must cast the extract pointer value, which is returned as a void *, back to be its original type, e.g. a_c_type * in your example.

(If you want to wrap what is being pointed at consider NSData.)

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86