0

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

The Dreams Wind
  • 8,416
  • 2
  • 19
  • 49
Jakob
  • 1,858
  • 2
  • 15
  • 26
  • Does this answer your question? [How to pass arguments when calling function with timer in objective c](https://stackoverflow.com/questions/1527175/how-to-pass-arguments-when-calling-function-with-timer-in-objective-c) – Cristik Aug 31 '22 at 15:25

1 Answers1

2

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;
    ...
The Dreams Wind
  • 8,416
  • 2
  • 19
  • 49
  • By the way, be advised that ARC knows nothing about the dynamically allocated C-arrays. Don't forget to free the memory when invalidating the timer. – The Dreams Wind Sep 04 '22 at 17:05