Run Pusher on Background Thread iOS - ios

I am rendering html pages on main thread. Hence I cannot run Pusher on the same thread as the main thread as it keeps dropping messages.
Is there any way of running always running Pusher on a background thread in iOS?
I have tried Grand Central Dispatch but it does not work as after initialising, Pusher comes back on the main thread.
Thank you
this is what I have so far.
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
client = [PTPusher pusherWithKey:#"xxxxxxxx" delegate:self encrypted:NO];
client.reconnectAutomatically = YES;
client.reconnectDelay = 1; // defaults to 5 seconds
[client connect];
PTPusherChannel *channel = [client subscribeToChannelNamed:[NSString stringWithFormat:#"Company_%#", [Settings sharedSettings].company.companyID]];
[channel bindToEventNamed:#"ServicePrint" handleWithBlock:^(PTPusherEvent *channelEvent) {
NSLog(#"[pusher event] Received event %#", channelEvent);
//do some work here
}];
dispatch_async( dispatch_get_main_queue(), ^{
// Add code here to update the UI/send notifications based on the
// results of the background processing
});
});

I ended up using it on the Main thread and dropped a lot of other functionality on the main thread. Seems to be working fine so far.

Related

Async calls on Objective-C

I'm implementing a mic plugin for a game and since the [capture_session startRunning] function is a long call, I'm wrapping it in an async call, but it is still laggy.
Commenting the code solves the lag, so I'm pretty sure this is the chunk that causes it.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[capture_session startRunning];
is_recording = true;
NSMutableDictionary *event = [Utils newEvent:EVENT_NAME];
event[PHASE_KEY] = #"started";
event[IS_ERROR_KEY] = #((bool)false);
[Utils dispatchEvent:lua_listener event:event];
});
Btw, I don't know much the language so I could be doing some very silly things here.
Really appreciate any help!
try this?
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
...
NSLog(#"current thread ---%#", [NSThread currentThread]);
});
You use concurrent queue and async method, those code you put in block should be run in a new thread.

Dispatch Queue and NSOperation queue

I am creating a serial queue in which i add two task as shown below
dispatch_queue_t serial = dispatch_queue_create("com.apple.serial", DISPATCH_QUEUE_SERIAL);
**//Task 1**
dispatch_async(serial, ^{
[NMUserAPIManager getUserProfileData:^(NMUser *objUser) {
NSLog(#"Get User Profile .....");
_objUser = objUser;
}];
});
**//Task 2**
dispatch_async(serial, ^{
[NMUserAPIManager getUserRecentTransactionData:^(NSDictionary *responseDictionary) {
_accountTableView.hidden = NO;
[self recentTransactionSetup:responseDictionary];
NSLog(#"Get User Recent transaction");
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadTableData];
});
}];
});
Inside that two task i am calling web service with NSURLSession. Problem is that before my Task 1 completion handle Task2 completion handle get called. According to theory by using serial queue each task waits for the previous task to finish before being executed. It my understanding is correct.
NSURLSession's already run on a background thread, so the issue you are seeing here is that as far as your serial queue is concerned once you call 'getUserProfileData:' technically the work for that block in your queue is finished because the NSURLSession is running on a different thread. If your main goal here is to simply call your second task after your first one completes I don't think you need your own queue you would probably be better off simply doing something like:
[NMUserAPIManager getUserProfileData:^(NMUser *objUser) {
NSLog(#"Get User Profile .....");
_objUser = objUser;
[self getUserTransactions];
}];
-(void)getUserTransactions
{
[NMUserAPIManager getUserRecentTransactionData:^(NSDictionary *responseDictionary) {
_accountTableView.hidden = NO;
[self recentTransactionSetup:responseDictionary];
NSLog(#"Get User Recent transaction");
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadTableData];
});
}];
}
EDIT:
If you are looking for something a little more robust I would check out this post for how you can subclass NSOperation to make your own Asynchronous Operation which you can then use with an NSOperationQueue.

How to make api calls synchronously in background?

I have four api calls to make. They should be in following order:
apiSyncDataToCloud;
apiSyncImagesToServer;
apiDeleteDataFromCloud;
apiSyncDataFromCloudInBackground;
Each one of them is to be called irrespective of the fact that previous one finishes successfully or fails.
Also, each one of them have success and failure completion blocks.
In success completion block database is updated.
All this process has to be performed in background and has to be done a no of times.
Api calls are of course performed in background but once a call completes database update is performed on main thread thereby freezing the app.
So, I went with several solutions:
Tried following code:
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{
[self apiSyncDataToCloud];
}];
[queue addOperationWithBlock:^{
[self apiSyncImages];
}];
[queue addOperationWithBlock:^{
[self apiDeleteDataFromCloud];
}];
[queue addOperationWithBlock:^{
[self apiSyncDataFromCloudInBackground];
}];
But this only guarantees that api method calls will be performed in order. But their result follows no specific order. That is, method calls will be in the order specified but success block of apiSyncImagesToServer may be called before success block of apiSyncDataToCloud.
Then I went with following solution:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self apiSyncDataToCloud];
});
and in the success and failure blocks of apiSyncDataToCloud I have called apiSyncImagesToServer. This too did'nt work.
Now I am simply going with my last solution. I am just calling apiSyncDataToCloud.
In success completion block this method first updates the database and then calls other api.
In failure completion block this method simply makes the api call without updating the database.
For example-
structure of apiSyncDataToCloud is as follows:
-(void)apiSyncDataToCloud{
NSLog(#"method 1");
NSMutableDictionary *dicDataToBeSynced = [NSMutableDictionary dictionary];
dicDataToBeSynced = [self getDataToBeSynced];
if (dicDataToBeSynced.count!=0) {
if ([[StaticHelper sharedObject] isInternetConnected]) {
[[ApiHandler sharedObject] postRequestWithJsonString:API_SYNC_DATA_TO_CLOUD andHeader:[UserDefaults objectForKey:kAuthToken] forHeaderField:kAccessToken andParameters:dicDataToBeSynced WithSuccessBlock:^(NSURLResponse *response, id resultObject, NSError *error) {
NSLog(#"Data synced successfully to server");
[self updateColumnZSYNC_FLAGForAllTables];//updating db
[self apiSyncImagesToServer];//api call
} andFailureBlock:^(NSURLResponse *task, id resultObject, NSError *error) {
NSLog(#"Data syncing to cloud FAILED");
[self apiSyncImagesToServer];//simply make api call without updating db
}];
}
}else{
[self apiSyncImagesToServer];make api call even if no data to be synced found
}
}
Similary, inside apiSyncImagesToServer I am calling apiDeleteDataFromCloud.....
As a result my problem remained as it is. App freezes when it comes to success block updating db, downloading images...all operations being performed on main thread.
Plz let me know a cleaner and better solution.
You can create your own custom queue and call request one by one.
i.e.
dispatch_queue_t myQueue;//declare own queue
if (!myQueue) {//check if queue not exists
myQueue = dispatch_queue_create("com.queue1", NULL); //create queue
}
dispatch_async(myQueue, ^{[self YOUR_METHOD_NAME];});//call your method in queue block
If you want update some UI after receiving data then update UI on main Thread.
1) Better to use AFNetworking for this kind of situations. Because AFNetworking provides better way to handle Main & Background Threads.
AFNetworking supports success and failure blocks so you can do one by one WS Api calls from success and failure of previous WS Api call. So during this time period show progress HUD. Success of last API then update DB and hide progress HUD.
2) If you need to use NSOperationQueue and NSInvocationOperation
and follow this link. https://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift
Api calls are of course performed in background but once a call
completes database update is performed on main thread thereby freezing
the app.
Then why not perform it in a separate queue?
Try using
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//your code
});
to perform time-consuming tasks and
dispatch_async(dispatch_get_main_queue(), ^{
//your code
});
to only update UI.

How to run a process in background thread iOS

I want to run a task after 6sec in background in a separate thread. I used this code for that.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self getUnsyncNamesFromServer];
}
I am not sure this run in a background thread. Do i need to use dispatch_async for this purpose. What is the best approach for this kind of situation.
dispatch_async is what you want. In the code you've used, the method inside the block will be after 6 seconds on the main queue.
For the background queue, use the follow:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{
[weakSelf getUnsyncNamesFromServer];
});
For further reference, here's the GCD Apple Doc: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_async
Your code would run in the main thread, i.e., not in background, because you are using dispatch_get_main_queue.
Instead of using the main queue, I would create a new one. The code would be something like:
dispatch_queue_t unsyncNamesQueue =
dispatch_queue_create("UnsyncNamesFromServer", DISPATCH_QUEUE_SERIAL);
//....
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC),
unsyncNamesQueue, ^{
[weakSelf getUnsyncNamesFromServer];
}
);
Be sure to read https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
This line will put your task on main thread not on separate thread
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
To put in secondary thread you have to put on global concurrent queue or make your own private queue.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC),dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //Put on global queue to run seprate thread
[self getUnsyncNamesFromServer];
}
Now to run in background(when application is in background state) you do not need to run on separate thread but if your application is taking too much time to do a task on main thread than you should put on separate thread as it is not advisable to block main thread for too much time.
Your code will not run in background state of application for that you need to register with iOS by calling beginBackgroundTaskWithExpirationHandler:
// Declare property in your class
#property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
-(void)yourfunction{
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC),dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //Put on global queue to run seprate thread
[weakSelf getUnsyncNamesFromServer];
if (weakSelf.backgroundTask != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:weakSelf.backgroundTask];
weakSelf.backgroundTask = UIBackgroundTaskInvalid;
}
});
}

dispatch_async NSURLConnection - download don't start

I'm trying to download information in background from a url.
I've read about GCD, Runloops and threads and decided that dispatc_async is my way to go.
After receiving data I aalso want to update the gui.
But... the NSUrlConnection don't seem to start at all. The delegate don't receive any calls.
I'v used this NSUrlRequest and NSUrlConnection in a synchronous way and the delegate got the data excpected.
Here is my code, a method in a viewcontroller;
- (void)dispatch: (NSURLRequest *) pRequest respondTo: (VivaQuery *) pQuery {
dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(downloadQueue, ^{
NSURLConnection *tConnectionResponse =[[NSURLConnection alloc] initWithRequest: pRequest delegate: pQuery];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Got to main thread.");
[pQuery requestEnd]; // Will update gui, i e aUIView setNeedsDisplay
});
});
}
Anyone got an idea?
Thanks in advance.
Kind regards,
Jan Gifvars
Stockholm
NSUrlConnection does its work asynchronously on it's own background thread so you do not need to create it in a background thread.

Resources