Async dispatch queue triggering error - ios

I am trying to code a simple iPhone app that does some modification to file contents in the app sandbox.
I need to make the process lazy. It is also important to ensure serialisation of consecutive file add/modify operation.
I've got this method:
#import "ProcessData.h"
#import <dispatch/dispatch.h>
#interface ProcessData ()
#end
dispatch_queue_t backgroundQueue;
NSLock *lock;
#implementation ProcessData
-(int)newEffects: (int) idNo : (NSString*) someData
{
[lock lock];
dispatch_async(backgroundQueue, ^(void)
{
#try
{
DiskAccess *dAccess = [[DiskAccess alloc] init];
//some operations here
[dAccess release];
}
#catch (NSException *exception)
{
}
#finally
{
printf("done with this stuff!");
}
})
[lock release];
}
#end
When I run this code, the application crashes unceremoniously and I get to see this:
0x1b1f2b5: cmpl $1, 36(%esi) Thread 1: EXC_BAD_ACCESS(code=2,address=0x24)
However, if I change the line:
dispatch_async(backgroundQueue, ^(void)
TO
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
...the system runs without a hiccup.
I'd like to know:
How to get my background queue to work. What am I doing wrong here?
If I use dispatch_get_global_queue and if there are multiple, back
to back file access requests, how can I ensure that the operations
are carried out sequentially?

Am I right that you initialize backgroundQueue nowhere? You must initialize backgroundQueue before using it. For example add code
backgroundQueue = dispatch_queue_create(#"Background queue name", NULL);
and only after that call
dispatch_async(backgroundQueue, ^{
//some code here
});
Perhaps a similar error with lock.

Related

iOS How to get the background dispatch queue completed Status

I have created A Queue like this
dispatch_queue_t myBackgroundQueue;
myBackgroundQueue = dispatch_queue_create("com.google.task", NULL);
dispatch_async(myBackgroundQueue, ^(void) {
});
this will be called on button click and i would like to know the current background running queues. Thank
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
// Check that there was not a nil handler passed.
if( completionHandler )
{
// This assumes ARC. If no ARC, copy and autorelease the Block.
[completionHandler performSelector:#selector(rmaddy_callBlockWithBOOL:)
onThread:origThread
withObject:#(ok) // or [NSNumber numberWithBool:ok]
waitUntilDone:NO];
}
});
});

In unit test, execute the block passed in queue with dispatch_asyc

If I dispatch_async a block on main queue like this:
-(void) myTask {
dispatch_async(dispatch_get_main_queue(), ^{
[self.service fetchData];
});
}
In unit test, I can execute the block passed in main queue by manually run the main loop like this:
-(void)testMyTask{
// call function under test
[myObj myTask];
// run the main loop manually!
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
// now I can verify the function 'fetchData' in block is called
...
}
Now, I have another similar function which dispatch block to an sequential queue other than main queue:
-(void) myTask2 {
dispatch_async(dispatch_queue_create("my.sequential.queue", NULL), ^{
[self.service fetchData];
});
}
In unit test, how can I execute the block manually now?
-(void)testMyTask2{
// call function under test
[myObj myTask2];
// How to manually execute the block now?
}
=== Clarify ===
The reason why I want to manually execute is because I don't like any Wait-For-Timeout way doing the test. Because waiting time is depending on CPU speed, on different machines could be different. I'd like to manually execute the block passed to queue (the same way as how I did for the main queue test case) and then verify the result.
You could create the queue in your test function.
-(void) myTask2:(dispatch_queue_t*)queue {
dispatch_async(*queue, ^{
[self.service fetchData];
});
}
-(void)testMyTask2{
dispatch_queue_t queue = dispatch_queue_create("my.sequential.queue", NULL);
[myObj myTask2:&queue];
dispatch_sync(queue, ^{
});
}
(Just realised currentRunLoop is not needed)
For execute test in async block use XCTestExpectation class
-(void) myTask2 {
XCTestExpectation *expectation = [self expectationWithDescription:#"catch is called"];
dispatch_async(dispatch_queue_create("my.sequetial.queue", NULL), ^{
[self.serviceClient fetchDataForUserId:self.userId];
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:Timeout handler:^(NSError *error) {
//check that your NSError nil or not
}];
}
Hope this help

how to know dispatch_async is running ios

I am looking for a small scenario that how can we trace the "dispatch_async" is running or not?.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
//back ground process
});
In my case, my app will be in foreground I started the back ground thread and when I bring app from background to foreground I need to check whether it is still running or not. I should not call the same process if it is still running. any idea?
The easiest way to do this (without keeping a reference to every dispatch or a flag for entering/leaving asynchronous tasks) is by using dispatch_group notifications. See the example link and code below:
- (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{
// 1
__block NSError *error;
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSInteger i = 0; i < 3; i++) {
NSURL *url;
switch (i) {
case 0:
url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
break;
case 1:
url = [NSURL URLWithString:kSuccessKidURLString];
break;
case 2:
url = [NSURL URLWithString:kLotsOfFacesURLString];
break;
default:
break;
}
dispatch_group_enter(downloadGroup); // 2
Photo *photo = [[Photo alloc] initwithURL:url
withCompletionBlock:^(UIImage *image, NSError *_error) {
if (_error) {
error = _error;
}
dispatch_group_leave(downloadGroup); // 3
}];
[[PhotoManager sharedManager] addPhoto:photo];
}
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{ // 4
if (completionBlock) {
completionBlock(error);
}
});
}
Note how:
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{ // 4
if (completionBlock) {
completionBlock(error);
}
});
will not be called until after
dispatch_group_leave(downloadGroup); // 3
is called.
You should setup your threading to where you can work with callbacks like this to determine states. You should try to avoid using boolean flags at all costs, as this is exactly what dispatch groups are for. It's also hard to keep track of numerous asynchronous calls using boolean states.
link: dispatch groups
The question is wrong - dispatch_async is running while you call it and stops running when the call returns, which is practically immediately. What you really want to know is whether the dispatched block is running or not. The simplest way is something along the lines of
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
[self blockIsRunning:YES];
// do stuff
[self blockIsRunning:NO];
});
or if you want to know whether the block has run once, you would do something like
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
[self blockStarted];
// do stuff
[self blockFinished];
});
Alternatively, use NSOperationQueue and a subclass of NSOperation so instead of an anonymous block you have a proper object that you can ask whether it is ready, cancelled, executing, or finished.

Testing background save of Core Data entity with Kiwi

I'm struggling to figure out the best method to test interacting with Core Data in a background thread. I have the following class method:
+ (void)fetchSomeJSON
{
// Download some json then parse it in the block
[[AFHTTPClient sharedClient] fetchAllThingsWithCompletion:^(id results, NSError *error) {
if ([results count] > 0) {
NSManagedObjectContext *backgroundContext = //... create a new context for background insertion
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(background, ^{ // If I comment this out, my test runs just fine
//... insert and update some entities
for (NSString *str in results) {
NSManagedObject *object = //...
}
});
}
}];
}
I'm currently testing this method with the following Kiwi code:
describe(#"MyAction", ^{
__block void (^completionBlock)(NSArray *array, NSError *error);
beforeEach(^{
// Stub the http client
id mockClient = [AFHTTPClient mock];
[WRNAPIClient stub:#selector(sharedClient) andReturn:mockClient];
// capture the block argument
KWCaptureSpy *spy = [mockClient captureArgument:#selector(fetchAllThingsWithCompletion:) atIndex:0];
[MyClass fetchSomeJSON]; // Call the method so we can capture the block
completionBlock = spy.argument;
// run the completion block
completionBlock(#[#"blah"], nil);
})
// If I remove the dispatch_async block, this test passes fine.
// If I add it in again the test fails, probably because its not waiting
it(#"should return the right count", ^{
// entityCount is a block that performs a fetch request count
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
})
// This works fine, but obviously I don't want to wait a second
it(#"should return the right count after waiting for a second", ^{
sleep(1);
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
});
};
If I remove the dispatch_async line, then I can get my test to run quickly. The only way I can get my test suite to run when using dispatch_async is to sleep(1) after calling the completion block. Using sleep() makes me think that I'm not approaching it in the right way. I have tried using shouldEventually but this doesn't seem to re-fetch my count value.
Have you tried these asynchronous block macros?
#define TestNeedsToWaitForBlock() __block BOOL blockFinished = NO
#define BlockFinished() blockFinished = YES
#define WaitForBlock() while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !blockFinished)
I have tried several approaches to solving this, none feel right.
1) Move the dispatch_async to its own class
+ (void)dispatchOnMainQueue:(Block)block
{
if ([NSThread currentThread] == [NSThread mainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
+ (void)dispatchOnBackgroundQueue:(Block)block
{
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(background, block);
}
Then during test execution, swizzle the background dispatch to occur on the main queue. This worked, but was unpredictable. It also felt so wrong!
2) Move the setup code to Kiwi's beforeAll block, then sleep the main thread. This works as the Kiwi tests are run on the main thread, so we're effectively saying "let the background operations happen before carrying on with the tests". I think this is what I'm going to use. Yes it makes my unit tests run slower, but they pass when they should do, and fail when they should
describe(#"MyAction", ^{
__block void (^completionBlock)(NSArray *array, NSError *error);
beforeAll(^{
// Stub the http client
id mockClient = [AFHTTPClient mock];
[WRNAPIClient stub:#selector(sharedClient) andReturn:mockClient];
// capture the block argument
KWCaptureSpy *spy = [mockClient captureArgument:#selector(fetchAllThingsWithCompletion:) atIndex:0];
[WRNTaskImporter importAllTasksFromAPI];
completionBlock = spy.argument;
// run the completion block
completionBlock(#[#"blah"], nil);
// Wait for background import to complete
[NSThread sleepForTimeInterval:0.1];
})
// This works
it(#"should return the right count", ^{
// entityCount is a block that performs a fetch request count
NSInteger count = entityCount(moc, #"Task");
[[theValue(count) should] equal:theValue(4)];
})
};
The caveat of this approach is that it only works when you aren't changing any data before a test. Say for example I insert 4 entities, and want to check each entity was inserted as expected. This option would work here. If I needed to re-run the import method and check that the count hadn't increased, I would need to add another [NSThread sleepForTimeInterval:0.1] after calling the insertion code.
For normal block based Kiwi tests you should probably use either the expectFutureValue shouldEventually method, or KWCaptureSpy to test your code, but this may not help when calling nested blocks.
If anyone has a more appropriate method for testing cases like these I'm happy to hear it!

how to solve setUp block of ObjCHiredis redis

When I use ObjCHiredis redis to connect to a invalid IP and Port, it will blocked.
How to set it to nonblock mode? Thx
- (void)setUp {
NSLog(#"begin setUp");
NSString *ip = #"125.124.125.125";
self.redis = [ObjCHiredis redis:ip on:[NSNumber numberWithInt:123] db:[NSNumber numberWithInt:0]];
if(self.redis == nil)
{
NSLog(#"init redis error.");
return ;
}
NSLog(#"end setUp");
}
The easiest way to do this is probably going to be by running the connection on a separate thread and using a block to handle the response back on the main thread.
This is a helper method I regularly use to do any sort of async tasks.
I've adapted it so it should work for what you're trying do:
+(void)threadedConnect:(NSString*)ip On:(int)port DB:(int)db WithResponseTask:(void(^)(ObjCHiredis *redis))task
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
ObjCHiredis *redis = [ObjCHiredis redis:ip
on:[NSNumber numberWithInt:port]
db:[NSNumber numberWithInt:db]];
// Run completion block back on main thread with result as argument
dispatch_async(dispatch_get_main_queue(), ^{ task(redis); });
});
}

Resources