Home > Back-end >  How to pass a multidimensional C-array as NSTimer userInfo?
How to pass a multidimensional C-array as NSTimer userInfo?

Time:09-01

I need to call a function in Objective-C every x seconds, but this function needs to receive a 2D int as parameter.

- (void)myTimer:(int[2][3]) field {
   //Rest of the code
}

I tried to use the userInfo option to pass this array, but it looks like it only accepts NSObjects.

int Field[2][3];
memset(Field, 0x00, 6 * sizeof(int));
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(myTimer:) userInfo:Field repeats:YES];

//Error is: Implicit conversion of a non-Objective-C pointer type 'int (*)[3]' to 'id _Nullable' is disallowed with ARC

Is there a way to pass this 2D int or do I need to go with NSObjects or maybe a global variable?

Thank you

CodePudding user response:

I don't think it's possible to pass a stack-allocated array to NSTimer (Objective-C is not very friendly to stack-allocated objects in general. You can pass a pointer to such an array, but NSTimer can outlive almost all stacks in the application, and you may end up with a dangling pointer then) so you at least need to make this array static or global.

Then you can take a pointer to it, and wrap it with NSValue like this:

static int data[array_rows][array_columns] = { { 0, 1, 2 }, { 3, 4, 5 } };
NSValue *userInfo = [NSValue valueWithPointer:&data];

Alternatively you can allocate the array in the dynamic memory:

int (*array)[array_columns] = malloc(array_rows * array_columns * sizeof(int));
if (array) {
    int val = 0;
    for (int i = 0; i < array_rows;   i) {
        for (int j = 0; j < array_columns;   j) {
            array[i][j] = val  ;
        }
    }
}
NSValue *userInfo = [NSValue valueWithPointer:array];

As you already noticed, NSTimer takes Objective-C classes as arguments, so NSValue can be passed as is:

[NSTimer scheduledTimerWithTimeInterval:1
                                 target:self
                               selector:@selector(timerAction:)
                               userInfo:userInfo
                                repeats:YES];

Be advised that on the target side the array pointer looks somewhat different. For the static variable you need to dereference the pointer value:

- (void)timerAction: (NSTimer *)timer {
    NSValue *userInfo = timer.userInfo;
    int (*array)[array_columns] = *(int (**)[array_columns])userInfo.pointerValue;
    ...

And for the dynamic memory array it's already dereferenced:

- (void)timerAction: (NSTimer *)timer {
    NSValue *userInfo = timer.userInfo;
    int (*array)[array_columns] = userInfo.pointerValue;
    ...
  • Related