简体   繁体   中英

updating UI thread from within a C function in iOS

I am working with a C program to try and use it in my iOS application with as little modification as possible. The C program performs a lot of calculations on a set of inputs.

On the iOS side, I am using the following code to create a thread to run the calculations, and also to have a mechanism to report when it is complete (currently, it updates a UILabel os "testLabel" when complete):

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];

    });
});

This seems to work, I get my results, and my UI stays responsive.

However, I am wanting to communicate from the C routine back to the UI while the calculations are going on in order to get status as well as to pass some data back incrementally.

So my C program would be something like this:

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
    }
}

I saw a thread on here about passing "self", but I don't think the "self" if passed above would be my class "self". In addition, I tried that and got an error on the C-side of things, saying that it did not recognize the type "id". I changed the type of "id" to the class name, and it told me the parameter was wrong.

Any ideas on the best way to implement this?

Thank you for your help.

declare a global c void*

void* sipUACObj;

And assign it the objective-c class object in your class initializer

sipUACObj = self;

Now whenever you need to invoke something from C function do the following,

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

This will call the corresponding objective-C function and you can invoke ur main UI thread in that function.

You could create a singleton class and assign it to the void pointer in its initialization and then do the needful in ur C function.

Maybe what you want is to have a block as a callback for reporting back partial results to the caller. Something like this:

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
    }
}

Then the client could call startProgram using something like:

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

This way your code will have no dependency on what or how the client do and uses the progress callback for. Also it is nice dependency injection.

If using blocks is not possible (model code might need to be pure C to work on other platforms?) then you can switch the block for a function pointer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM