UI is not updating while some function takes time to execution? - ios

I am doing some image processing and with this also showing the loading. Problem is that loading is not updating.
for (ALAsset *asset in assets) {
weakSelf.HUD.labelText = [NSString stringWithFormat:#"%d/%d",count,assets.coun
weakSelf.HUD.progress=(CGFloat)count/assets.count;
[objDoc setImageProcess:asset];
count++;
}
Here the HUD is not updating its value. If I put the delay then its showing. Here setImageProcess takes time while processing.

UI updates take place on the main thread in iOS and Mac OS. If you have time-consuming code that runs on a background thread, you can send messages to the main thread to update the UI and it works perfectly.
If you are running your time-consuming code on the main thread, UI changes get accumulated, and only get rendered to the screen when your app returns and visits the event loop.
So, if you have a loop that does a bunch of time-consuming tasks and doesn't return until the whole loop is finished, it doesn't work because the UI updates don't take place until you return.
You need to refactor your code to return between iterations. Something like this:
Create an instance variable assetCount:
#interface myClass: UIViewController;
{
NSInteger assetIndex;
}
#end.
Then
-(void) viewDidLoad;
{
assetIndex = 0;
[self processAssets];
}
- (void) processAssets;
{
if (assetIndex >= assets.count)
return;
ALAsset *asset = assets[assetIndex];
weakSelf.HUD.labelText = [NSString stringWithFormat:#"%d/%d",count,assets.coun
weakSelf.HUD.progress=(CGFloat)count/assets.count;
[objDoc setImageProcess:asset];
assetIndex++;
count++;
//The following method call queues up a method call
//for the next time your app visits the event loop. (plus an optional delay)
[self performsSelector: processAssets
withObject: nil
afterDelay: 0];
}
The method above processes 1 asset, then queues a delayed call to itself. Even though the delay value is 0 it still fixes your problem. That's because the performSelector:withObject:afterDelay: method always returns immediately, and queues up the method call for the next pass through the event loop. In the next pass through the event loop, the system does housekeeping like updating the screen, then checks for pending calls like this one. If there is a delay it will start a timer. If not, it will trigger your method call.
You have a variable count in the code you posted that might work as an array index. I added a new instance variable assetIndex to track the current array index. Your code also uses the term weakSelf, suggesting that this code is being executed from a block. It might be that there is a cleaner way to handle this, but you would need to provide more information.

For all UI changes, you have to call in mainthread. Verify that the current functions is called in main thread:
BOOL isMainThread = [[NSThread currentThread] isMainThread]

Related

make a simple NSInteger counter thread safe

I define a NSInteger counter and updated its value in a callback like the following code shows (callback is in another thread):
-(void) myFunc {
NSLog(#"initialise counter...");
// I try to use volatile to make it thread safe
__block volatile NSInteger counter = 0;
[self addObserver:myObserver withCallback:^{
// this is in another thread
counter += 1;
NSLog(#"counter = %d", counter);
}];
}
I use volatile keyword to make the counter thread safe, it is accessed in a callback block which belongs to another thread.
When I invoke myFunc two times:
// 1st time call
[self myFunc];
// 2nd time call
[self myFunc];
the output is like this:
initialise counter...
counter = 1;
counter = 2;
counter = 3;
counter = 4;
counter = 1; // weird
initialise counter...
counter = 2; // weird
counter = 3;
counter = 1; // weird
counter = 4;
It looks like the 2nd time call produce a counter with wrong initial value, and the output before counter=4 is counter=1 which is also weird.
Is it because my code is not thread safe even with volatile keyword? If so, how to make my counter thread safe? If it is thread safe, why I get weird output?
For the simple case of an atomic counter, GCD is overkill. Use the OSAtomic functions:
-(void) myFunc {
static int64_t counter;
[self addObserver:myObserver withCallback:^{
// this is in another thread
int64_t my_value = OSAtomicIncrement64Barrier(&counter);
NSLog(#"counter = %d", my_value);
}];
}
Note that the code logs the result of the increment function rather than the static variable. The result gives you the atomic result of your specific operation. Using the static variable would give you a snapshot of the counter that's not atomic with respect to your increment operation.
First of all using a local variable is corrupted. It will be removed from stack, when the function returns. Therefore the block copies the variable's value (capture) when the block definition is executed (counter = 0) and works on the copy.
If you have a shared resource as the counter is, you have to put accesses to it into a block.
// global
dispatch_queue_t counterQueue;
int counter;
// initialize
counterQueue = dispatch_queue_create( "com.yourname.counterQueue", DISPATCH_QUEUE_SERIAL);
counter = 0;
// Whenever you read or write to counter
dispatch_async( counterQueue,
^{
counter++;
NSLog( #"%d", counter" );
}
// or
int lastValue;
dispatch_sync( counterQueue,
^{
lastValue = counter;
}
// Do something with it.
There are lots of things wrong with your code. It looks like you're calling myFunc repeatedly. Each time you do, it creates a new instance of the counter.
Make your counter an instance variable or app-wide global.
A simple way to make incrementing (and logging) the counter thread-safe is to make the body of the observer use dispatch_async(dispatch_get_main_queue()<your code here>). That way the code that messes with the counter always runs on the main thread, even if it's called from other threads. This isn't the most performant way to handle it, but it's easy.
Otherwise you're going to need to use locks or some other concurrency technique. That requires a strong understanding of thread safety, which your post, frankly, shows that you don't have. (Not to be mean, it's one of the more difficult subjects in computing.)
EDIT:
As Avi points out in his comment, using the main queue to manage the counter would cause the other threads to block waiting on the main thread, and is not a very good solution. (It would work, but would take away just about all the performance benefit of using multiple threads)
It would be better to set up a single serial queue and make that a lazily loaded property of the object that manages this counter, protected with dispatch_once(). However, I don't have enough coffee on-board to write out that code in a forum post.

iOS Why wouldn't exiting a method in the main thread from a sub-thread work?

I'm initiating an asynch thread using grand central dispatch in objective-c using the following code:
dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
}
For a very long time I was having trouble correctly exiting the IBAction that triggers this. I do a lot of the code in the main thread wrapped inside this GCD thread using this code:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}
What I originally tried to do was simply put the return; statement inside this mainQueue block. After a lot of fiddling I discovered that to break out of the IBAction that contains all this the return; needs to be in the GCD queue.
Why is this? I thought that return would exit methods regardless of where it is in the program. Also, is it even possible to exit from a nested queue call like this?
A block is similar to a function. It is a different context from the code which defines it. A return statement within a block exits that block, not the method or function within which the block was defined. (If the block has a non-void return type, the return statement also gives the return value of the block.)
For example, consider:
void foo(void)
{
int (^block)(int, int) = ^int(int a, int b) { return a + b; }
printf("3 + 5 = %d\n", block(3, 5));
}
The return statement in the block does not return from foo(), it just returns from the block and gives the return value of the block. The block is like a little separate function except that its code is provided right in the middle of another function and it can capture local variables from the context of its definition.
Now, the block given to dispatch_async() does not take arguments or return a value, but the flow control of the return statement is the same. It returns from that block, not from the method or function containing the call to dispatch_async(). In particular, since dispatch_async() runs the block asynchronously, it is quite possible (even likely) that the block won't be run until well after the method or function that called dispatch_async() has already exited.

Methods that use completion blocks and return an object

I have a method that inits the object and it has a completion block: typedef void(^initCompletionHandler)(BOOL succesful);
In this method I want to call the handler but I am not sure how to do it because if I call it before the return the object won't be finished initialising which is used immediately in the next line. I also obviously can't call the handler after the return. i,e:
if(haveError){
handler(NO);
}
else{
handler(YES);
}
return self;
Is there any way I can return and call the handler at the same time?
A couple of observations:
I'm unclear as to why you say "because ... the return object won't be finished initialising." You're doing the initialization, so just ensure it finishes all of the associated initialization before calling that handler. If the issue is that the caller won't have a valid reference to that object yet, you could always include a reference to it in the parameter of the block, e.g.
typedef void(^initCompletionHandler)(MyObject object, BOOL succesful);
and then supply that parameter, e.g.:
if (haveError){
handler(self, NO);
} else {
handler(self, YES);
}
Also, you say "I obviously can't call the handler after the return". But you can. You could just do a dispatch_async, if you wanted:
dispatch_async(dispatch_get_main_queue(), ^{
if (haveError){
handler(NO);
} else {
handler(YES);
}
});
return self;
That's a little inelegant, as if you call it from another thread, you have some potential race conditions that you might have to coordinate/synchronize, but you get the idea: You don't have to call the handler synchronously.
Having made both of those observations, I must confess that I'm not a fan of having init actually launching some asynchronous process and having its own completion block. I'd be inclined to make those two different steps. If you look at the Cocoa API, Apple has largely shifted away from this pattern themselves, generally having one method for instantiation, and another for starting the asynchronous process.

Objective-C: Method's return value and Completion block, how are they executed?

I make an photography app in iPhone and I have these 3 classes: ViewController, CaptureManager, and ImgProcessor.
ViewController:
-(IBAction)takePic:(id)sender{
images = [captureManager takeMultipleImagesWithCompletion:^{
//Some UI related code..
[imgProcessor process:images];
}];
}
CaptureManager:
-(NSArray *)takeMultipleImagesWithCompletion:^(void)completionHandler{
// take picture codes...
completionHandler();
return arrayOfImagesTaken;
}
So far it works as desired: imgProcessor processes the images taken by captureManager. But I don't quite get the idea how this works. Bcos I called completionHandler before I return the array of images taken. How did this code executed? Is there a better solution to this?
Thanks!
You don't need to return the value images. You can pass it as an argument for the cmpletionHandler block.
-(void)takeMultipleImagesWithCompletion:(void (^)(NSArray *images))completionHnadler{
// take picture codes...
completionHnadler(arrayOfImagesTaken);
}
You can call it like this :
-(IBAction)takePic:(id)sender{
[captureManager takeMultipleImagesWithCompletion:^(NSArray *images){
[imgProcessor process:images];
}];
}
How it works ?
Here the block is used as a callback, it defines the code to be executed when a task completes. When the takeMultipleImagesWithCompletion is finished running, the block completionHnadler will be called.
Since your takeMultipleImagesWithCompletion executes the completion block synchronously, it doesn't need to take a completion block. It can just return the arrayOfImagesTaken and the caller can do whatever it wants with it.

questions/problems while implementing reusable thread-safe core data pattern

I'm having trouble implementing the thread-safe core data concepts outlined in this tutorial. My goal is to have a reusable portion of code that can take arguments in, do core data operations (adds, updates, deletes) and then callback asynchronously when done.
So heres the block that 'safely' modifies core data objects:
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
NSManagedObjectContext *context = [NSManagedObjectContext context];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];
[defaultContext observeContext:context];
 
block(context);
if ([context hasChanges])
{
[context save];
}
}
From the way I understand it, this executes a block of code? I don't understand how the 'context' being passed in figures in. Is this part of the block's signature?
So here is the wrapper that does the operation in the background and adds a completion call:
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];
dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}
Here is an example using it:
NSArray *listOfPeople = ...;
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
self.people = [PersonEntity findAll];
}];
What is the 'localContext' passed in here? I think most of my issues here revolve around not understanding blocks.
A brief look at that tutorial shows it is talking about magical record. I have never used it, so I can't speak for it.
// This declares a class method that returns void and takes a block as parameter.
// The block returns void and has one parameter, namely, a pointer to an
// NSManagedObjectContext object.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
You would call that method like this...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Some code
}];
That means you are passing in a block of code to the function. At some point it will execute the bock of code you gave it. When it does, it's going to pass a managed object context into the block so it can do something with it.
Now, look at the implementation of that method...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
// Create a MOC - note there is no concurrency type, so it will get
// NSConfinementConcurrencyType, which means it must be used exclusively
// from the thread in which it was created. Since it is a local variable
// and it gets destroyed after this function is called, that should be cool
// PROVIDED the using block does not do anything untoward with it.
NSManagedObjectContext *context = [NSManagedObjectContext context];
// Set the merge policy
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
// MR must set some default context...
// Some how the above context needs a persistent store to save...
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];
// Probably setting up notification handler for DidSave
[defaultContext observeContext:context];
// Now, this is where the block you passed in gets called.
// Note, that the managed object context has already been setup for you.
// Now that it's setup, the block of code that you passed in is going
// to be called, and it will be given a context that it can use to execute
// code in the calling thread.
block(context);
// If you changed something to the context in your block of code, the save.
if ([context hasChanges])
{
[context save];
}
}
Let's revisit a our code that called this method...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Now, the saveDataInContext method has been called. However, inside
// that method, a call was made to the block that was passed in.
// That would be this here block of code. So, if you look up in
// the method, where is calls "block(context)" this block of code will
// be executed right there. Mentally, you can cut and paste this code
// in that spot.
// The context parameter is the context that was passed to this block.
// you can use it to do any Core Data stuff...
}];
Now, this code is very similar, but it takes two blocks. One is used to execute some code on the context, and the other is a block that will get executed with the asynchronous save has completed.
saveBlock should be familiar. It's the same concept as in the above example.
completion is a block, that returns void, and takes not parameters. It will get called when all the work has been done.
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
// Dispatch some work on one of the global concurrent queues. It will
// get done on some thread, nobody knows which one, but it does not matter
// because the code in this block calls saveDataInContext, and passes the
// block it was given that does some modifications to the context.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];
// Now, when the above work is done, we are still running in some random
// thread. I guess the library wants all callbacks to happen on the main
// thread, so this block is dispatched on the main thread. Note that it
// calls the second bock passed in as the completion block.
// So the <saveBlock> will be run on some random thread, and then, when
// it is done, the <completion> block will be called on the main thread.
dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}
Like earlier, when you call that method, you can mentally replace the with the first block you pass in, and replace with the second block.
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
// This is the first block. It gets executed where you see <saveBlock>
// being used in the earlier method. You are being given the already
// prepared MOC, and it's name is <localContext>. Do your managed object
// context stuff with it. Note that it will be running in some unknown thread.
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
// Now, this is the second block, which is run when all the core data saving
// has been completed. It will run on the main thread.
self.people = [PersonEntity findAll];
}];
Hopefully, that helps you understand what is happening, even though I don't know what magical record is really doing under the covers.
EDIT
In response to this comment...
I don't think I understand how these blocks work. If a block has this
method signature "+
(void)saveDataInContext:(void(^)(NSManagedObjectContext
*context))saveBlock" why is the block NOT using "context" or "saveBlock"? Which is the return value for a block and which is the
passed in value? – Mike S
First, the block does not have this signature...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
That is a class method. Let's break it down piece by piece. First, however, let's forget the block parameter, and use something easy, for comparison.
+ (void)foo:(NSInteger)someInteger;
That is a is a class method, foo:, which returns void and takes one argument. The type of that single argument is NSInteger. If I wanted to call it, I would do so like this:
[SomeClass foo:42];
Likewise...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
is a class method, saveDataInContext:, which returns void and takes one argument. The type of that single argument is void(^)(NSManagedObjectContext *context).
Now, don't let that gobbly-dee-gook fool you. It's just a type (albeit a somewhat confusing one to parse if you don't understand much C) So, what is void(^)(NSManagedObjectContext *context)
First, it is a block. If that (^) after the void were (*) it would be a function pointer.
Basically, it means that the type of that argument is a block that returns void and has one parameter, namely a pointer to a NSManagedObjectContext (with a name context).
So, if we read it out loud...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
is a class method, with selector saveDataInContext: which returns void and has one parameter, which has a name saveBlock and is of the type "block that returns void and has one parameter of type NSManagedObjectContext *."
Just like we call the first example like this...
[SomeClass foo:42];
we call the latter example like this...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// We are creating a bock of code, so stuff some code in here.
}];
Now, just like you passed the integer 42 to foo: you are passing the block in between the {} as the argument to saveDataInContext:.
Now, note that the signature of thesaveDataInContext: method wants a block that itself has a parameter. So, when you provide your block, you are basically saying, "Hey, here is a block of code for you to call, and when you do so, make sure you give me a pointer to a NSManagedObjectContext object that I can use.
What this means is that when your block is called, the calling code will call your block and provide a NSManagedObjectContext * to you with the variable name context.
Think of it like this, as a trivial example of saveDataInContext:.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock {
// Create a context to give the block we are going to call..
NSManagedObjectContext *moc = //
saveBlock(moc);
}
Now, when your code is called, you will get the moc object as your argument. Bascially, that method creates a managed object context, does all the thread safety stuff, then calls your block of code, and gives you a pointer to the managed object context that it has safely created. Your code is executed within the confines of that safe environment, using the MOC passed to it as a function (block) parameter.
I hope that didn't make it worse...

Resources