обновление потока пользовательского интерфейса из функции C в iOS - PullRequest
2 голосов
/ 10 мая 2011

Я работаю с программой на C, чтобы попытаться использовать ее в своем приложении для iOS с минимальными изменениями, насколько это возможно.Программа на C выполняет множество вычислений на множестве входных данных.

На стороне iOS я использую следующий код для создания потока для выполнения вычислений, а также для создания механизма отчета о его выполнении.завершен (в настоящее время он обновляет UILabel os "testLabel" после завершения):

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    char *testChar = startProgram( nx, ny, nz ); // this is where I call the C program 

    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *tempString = [[NSString alloc]initWithCString: testChar ];

        testLabel.text = tempString;

        [tempString release];

    });
});

Кажется, это работает, я получаю свои результаты, и мой пользовательский интерфейс остается отзывчивым.

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

Таким образом, моя C-программа будет выглядеть примерно так:

char* startProgram( int nx, int ny, int nz )
{
    setupEverything(); // this is just pseudo code for clarity
    for( int i = 0; i < nz; i++ )
    {
        doMajorCalculations();

        reportBackToUI( someResults ); // This is what I would LIKE to do
    }
}

Я видел здесь поток про передачу "self", но я не думаю, что "self", если передается вышебыл бы мой класс "я".Кроме того, я попробовал это и получил ошибку на стороне C, говоря, что он не распознает тип «id».Я изменил тип «id» на имя класса, и он сказал мне, что параметр был неверным.

Есть какие-нибудь идеи о том, как лучше всего это реализовать?

Спасибо за вашу помощь.

Ответы [ 2 ]

3 голосов
/ 10 мая 2011

объявить глобальную пустоту *

void* sipUACObj;

И присвойте ему объект классаjective-c в инициализаторе класса

sipUACObj = self;

Теперь, когда вам нужно вызвать что-то из функции C, сделайте следующее:

  ObjcClass *obj = (ObjcClass*) sipUACObj;
  [obj someMethod:arg1 Arg2:arg2];

Это вызовет соответствующую функцию target-C, и вы можете вызвать основной поток пользовательского интерфейса в этой функции.

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

2 голосов
/ 10 мая 2011

Возможно, вам нужно иметь блок в качестве обратного вызова для сообщения частичных результатов вызывающей стороне. Примерно так:

char* startProgram( int nx, int ny, int nz, void(^reportBackToUI)(int) )
{
    setupEverything(); // this is just pseudo code for clarity
    for( int i = 0; i < nz; i++ )
    {
        doMajorCalculations();

        reportBackToUI( someResults ); // This is what I would LIKE to do
    }
}

Тогда клиент может позвонить startProgram, используя что-то вроде:

return startProgram(42, 12, 20, ^(int someResults) {
           dispatch_async(dispatch_get_main_queue(), ^{
              // Update UI in some way.
           });         
       });

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

Если использование блоков невозможно (возможно, для работы модели на других платформах код модели должен быть чисто C) , тогда вы можете переключить блок на указатель на функцию.

...