0

In Windows, it is possible to run events within code ..

//PeekMessage loop example
while (WM_QUIT != uMsg.message)
{
     while (PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
     {
          TranslateMessage (&uMsg);
          DispatchMessage (&uMsg);
     }
}

In Objective-C for iOS is there a way to cause to run events intermittently in, for instance, a for-loop?

I have some deeply nested code that takes some time to run and I'd like it have it update the progress intermittently. Redesigning the deeply nested code isn't really an option and it runs on other operating systems.

B. Nadolson
  • 2,988
  • 2
  • 20
  • 27

3 Answers3

1

So, you basically want to run a long task and update the progress accordingly. This can be done with GCD and NSOperationQueue in Objective-C. The below code gives you an example for that.

Here I will be using a function which takes a block as a input. The function contains asynchronous code.

typedef void(^ProgressBlock)(CGFloat progress); // defined block

- (void)executeTaskWithProgress:(ProgressBlock)progress; // defined function

You can run your task asynchronously in the following two ways:

  1. Using GCD:

    - (void)executeTaskWithProgress:(ProgressBlock)progress {
    
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
                  // your long running task
    
                  // the below line is for updating progress
                  dispatch_async(dispatch_get_main_queue(), ^{
                      progress(20.0);
                  });
            });
     }
    
  2. Using NSOperation:

    - (void)executeTaskWithProgress:(ProgressBlock)progress {
    
            NSOperationQueue *executionQueue = [[NSOperationQueue alloc] init];
            NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
               // your long running task
    
               // the below line is for updating progress
               [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                   progress(20.0);
               }];
            }];
    
            [executionQueue addOperation:operation];
     }
    

You can call the function in the following way:

[self executeTaskWithProgress:^(CGFloat progress) {
    [self.myLabel setText:[NSString stringWithFormat:@"%f completed", progress]];
    // myLabel is an UILabel object
}];

For more details on asynchronous programming using GCD in Objective-C, I suggest you to look into the following tutorial. Feel free to ask any doubts

KrishnaCA
  • 5,615
  • 1
  • 21
  • 31
  • Is that basically a way of starting a background thread using dispatch? Would I be able to pass it a selector or a C function to run? – B. Nadolson Feb 18 '17 at 17:23
  • You can run a C function inside the `dispatchQueue`. If it's a C++ function rename the .m file to .mm file and you will be to run a C++ function too – KrishnaCA Feb 18 '17 at 17:24
  • Also, `dispatchQueue` maintains the threads. Did you try using this code snippet for your task? – KrishnaCA Feb 18 '17 at 17:27
  • I haven't yet, but I'm sure you provided enough information I can make it work. Thanks! – B. Nadolson Feb 18 '17 at 17:33
0

You can do such a thing by using NSTimer as follows in your controller:

- (void)viewDidLoad {
    [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(timerCalled) userInfo:nil repeats:YES];
}

-(void)timerCalled
{
    NSLog(@"timer called");
}
Soheil Novinfard
  • 1,358
  • 1
  • 16
  • 43
0

I'm not familiar with modern Windows async programming techniques, or the PeekMessage function. You should explain what that does in general CS terms.

It sounds like that's a way to respond to system events while you are doing time-consuming tasks.

iOS uses a slightly different approach. It it a multithreaded OS that runs an "event loop" on the main thread. Each time through the event loop, the system checks for events that need to be responded to (touch events, notifications, data coming in on the WiFi or cell network, screen updates, etc.) and handles them.

You need to write your code that runs on the main thread to do short tasks in response to user actions or system events, and then return. You should not do time-consuming tasks on the main thread.

There is a framework called Grand Central Dispatch that provides high level support for running tasks on background threads (or on the main thread, for that matter.) You also have NSOperationQueues, which give you support for managing queues of tasks that are run either concurrently or in parallel, on the main thread or in the background.

The two OS's use a different paradigm for handling events and concurrency, and there is likely no simple "use this function instead" replacement for your current way of doing things.

You should probably refactor your long-running tasks to run on a background thread, and then send messages to the main thread when you want to update the user interface.

Duncan C
  • 128,072
  • 22
  • 173
  • 272