2012-01-31 3 views
2

Я хочу передать C-массивы методу в Objective-C после задержки. Как правило, я мог выполнять выбор: withObject: afterDelay, но я не могу каким-либо образом изменить массивы или преобразовать их в NSMutableArrays, NSDictionaries или любой другой объект Cocoa - они должны быть C-массивами. В моих исследованиях здесь, в StackOverflow и Google, я обнаружил, что одним из способов передачи примитива C является их объединение в NSInvocation. Я попытался сделать это с помощью кода ниже и установить аргументы в качестве указателей на передаваемые массивы.NSInvocation pass C-array до Objective-C method

float gun1_vertex[24][8] = { {data,...data},{data,...data}, ... {data,...data} }; 
float gunDown1_vertex[24][8] = { {data,...data},{data,...data}, ... {data,...data} }; 

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(testMethod:secondCArray:)]]; 
    [inv setSelector:@selector(testMethod:secondCArray:)]; 
    [inv setTarget:self]; 
    [inv setArgument:&gun1_vertex[0][0] atIndex:2]; 
    [inv setArgument:&gunDown1_vertex[0][0] atIndex:3]; 
    [inv performSelector:@selector(invoke) withObject:nil afterDelay:0.1f]; 

Мой тест приложение сохраняет сбой при попытке напечатать несколько значений из пройденных массивов ниже способом. Вероятно, я просто пропустил что-то совершенно очевидное. Может ли кто-нибудь пролить свет здесь?

- (void)testMethod:(float *)test secondCArray:(float *)test2 { 

    for (int a = 0 ; a < 10 ; a++) { 

     NSLog(@"%f %f",test[a],test2[a]); 

    } 

} 
+0

Вы можете изменить способ, чтобы принять объект? Если это так, вы можете вставить байты в 'NSData', а затем распаковать их с другой стороны. –

+0

@JoshCaswell: Или просто создайте промежуточный метод «thunk», который делает распаковку, и поворачивается и вызывает желаемый целевой метод. –

+0

Нет, я не могу изменить C-массивы. Синтаксис выглядит нормально для NSInvocation? Похоже, что он должен работать - указатель на первый элемент многодискового массива, а затем просто распечатывает несколько значений после перехода к testMethod. Я получаю EXC_BAD_ACCESS в строке NSLog. – PhilBot

ответ

3

Вы могли бы сделать что-то вроде этого:

-(void) testMethod:(NSData *) arrayone secondArray:(NSData *) arraytwo 
{ 
    float **gun1_vertex = (float **)[arrayone bytes]; 
    float **gunDown1_vertex = (float **)[arraytwo bytes]; 

    // ... 
} 

NSData *gun1data = [NSData dataWithBytes:(void *)gun1_vertex  length:sizeof(float) * 24 * 8]; 
NSData *gun1downData = [NSData dataWithBytes:(void *)gunDown1_vertex length:sizeof(float) * 24 * 8]; 

[inv setArgument:&gun1data atIndex:2]; 
[inv setArgument:&gun1downData atIndex:3]; 
+0

Спасибо, это то, что я искал в качестве примера для обертывания NSData. – PhilBot

+0

Построение 'NSData' с' dataWithBytes: 'будет * копировать * исходные массивы, что, безусловно, является чрезмерным, если исходные массивы являются статическими? Также типы переменных в 'testMethod' должны быть' float * '(массивы C являются прямоугольными, а не векторами векторов ...). – CRD

+0

@CRD массивы не являются статическими, они выделяются в стеке и будут уничтожены, когда функция завершается, делая их мусорными при выполнении метода testMethod. Таким образом, используется NSData. –

1

Чтобы сделать вызов после задержки, используйте dispatch_after блок:

double delayInSeconds = 0.1; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
     [self testMethod:&gun1_vertex[0][0] secondCArray:&gunDown1_vertex[0][0]]; 
    }); 
+0

Мне нравится решение, но, возможно, у ОП есть причина для использования NSInvocation. –

3

Ваша проблема не достаточно косвенность. setArgument принимает указатель на место значения, которое вы хотите установить в качестве аргумента, а значение в вашем случае также является указателем ... Использование переданного указателя и информации о типе setArgument может скопировать правильное количество байтов.

Так что вам нужно что-то вроде:

float *gun1_vertex_pointer = &gun1_vertex[0][0]; 
[inv setArgument:&gun1_vertex_pointer atIndex:2]; 
+0

Спасибо, что очищает мою оригинальную проблему с пониманием части setArgument вызова. – PhilBot

+1

Не понимаю. Почему вы получаете адрес первого элемента массива? Просто отправьте сам массив, что просто добавляет сложности. –

+0

'gun1_vertex_pointer' должно быть типа' float * ' – user102008

 Смежные вопросы

  • Нет связанных вопросов^_^