I want to do some task synchronously as :
[NSURLConnection sendSynchronousRequest:Request returningResponse:&response error:&error];
is deprecated what I can use in place of this.
Use dispatch_sync to perform synchronously tasks.
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(#"Required task code.");
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI in main thread.
// Add your UI Label Update code here..
});
});
Let me know if you need anymore help..
Using "NSURLSession-SynchronousTask" library produces me same results as NSURLConnection .
Related
In my document-based MacOS application, I have some big files that are loaded (especially recent files opened at application launch). I created ProgressController (a NSWindowController subclass) to inform user in a window that file loading is in progress. It is allocated by the makeWindowControllers method of the NSDocument subclass I use to manage documents. These are created when the user opens a file (and notably at startup when documents were displayed as the user did quit the application) and they load their content asynchronously in a background queue which in principle should not affect the main thread performance:
-(instancetype) initForURL:(NSURL *)urlOrNil withContentsOfURL:(NSURL *)contentsURL ofType:(NSString *)typeName error:(NSError *
{
if (self = [super init]){
... assign some variables before loading content...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{
[[[NSURLSession sharedSession] dataTaskWithURL:urlOrNil completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
self.content = [[NSMutableString alloc] initWithData:data encoding:encoder];
dispatch_async(dispatch_get_main_queue(), ^(){
[self contentIsLoaded];
});
}] resume];
});
}
return self;
}
In contentIsLoaded, the progress window is closed.
- (void) contentIsLoaded
{
... do something ...
[self.progressController close];
}
This behaviour is OK, the window is displayed and closed when necessary.
The problem occurs when I want to update the content of this window on the main queue. I tried setting a NSTimer but is is never fired, even though it is created in the main queue. So, in MyApplicationDelegate I created a GCD timer like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
if (self->timer !=nil) dispatch_source_cancel(timer);
self.queue = dispatch_queue_create( "my session queue", DISPATCH_QUEUE_CONCURRENT);
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, ^{
[self updateProgress];
});
dispatch_resume(timer);
…
}
In MyApplicationDelegate, the updateProgress method is defined as:
- (void) updateProgress
{
dispatch_async(self.queue, ^{
NSLog(#"timer method fired");
dispatch_async(dispatch_get_main_queue(), ^(){
NSLog(#"access to UI fired");
... update window (e.g. NSProgressIndicator)
}
});
if (self.shouldCancelTimer) dispatch_source_cancel(self->timer);
});
}
When running the application, The "Timer method fired" is logged every second. The "timer method fired" message (in the main queue) is logged once or twice only, then the logging seems suspended until the file has been loaded. Then this missing message appears several times in a row, as it was suspended before.
What did I wrong? I supposed that the background queue used for file loading should not affect the main queue and UI updates. Many applications behave like that and I need such behaviour as files in my App (strings, csv, json) can be hundreds of Mbytes!
For starters, have you looked into NSURLSessionTask's progress reporting APIs? There are a bunch of facilities for measuring and getting called back as data loads. It might be possible for you to avoid doing the polling, and just update your UI as these are called back - all on the main thread.
In fact, you might not even need one at all. As I recall, the networking operations carried out by NSURLSession are all done in the background anyways. I bet you can remove all of this, and just use some extra delegate callbacks from NSURLSession APIs to get this done. Way simpler too :)
Good luck!
I've downloaded the latest Parse SDK for OS X, and I'm trying to retain my login after app restarts (obviously). I've used Parse before and I haven't faced this problem, neither on iOS nor OS X.
On my app start:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[Parse setApplicationId:#"XXX" clientKey:#"XXX"];
}
In my first view controller:
-(void)viewDidAppear{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if(![PFUser currentUser]){
[self performSegueWithIdentifier:#"login" sender:nil];
}else{
...
}
});
}
My login succeeds, and at that point [PFUser currentUser] is valid. Then, I close the app (tried both killing and gracefully quitting). When I open it again, [PFUser currentUser] is nil. I've tried this many times, it yields the same results. Why?
After struggling for a long while, I've found the solution. I need to dispatch_async the user checking block and it starts working. So instead of:
dispatch_once(&onceToken, ^{
if(![PFUser currentUser]){
[self performSegueWithIdentifier:#"login" sender:nil];
}else{
...
}
});
I did:
dispatch_once(&onceToken, ^{
dispatch_async(dispatch_get_main_queue(), ^{
if(![PFUser currentUser]){
[self performSegueWithIdentifier:#"login" sender:nil];
}else{
...
}
});
});
And it started working. Interesting to see that something is still not initialized on viewDidAppear synchronously on main queue (yes, it IS the main queue, double checked that), but is initialized somewhere after posting to the same queue asynchronously. Parse definitely needs more quality control of their SDK.
Having two devices that need to keep transferring data while in background or in LockScreen.
The main resource about backgrounding is available on https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
So far I'm looking forward to understand how is it expected to implement such above mentioned behaviour: in a scenario where a transfer is in progress and one of the apps (or both) goes into background. Obviously we have resumable transfer management working already.
I've been collecting stubs and answers about and I've ended up with the following:
Ensure every socket is backgroundable.
[socket performBlock:^{
[socket enableBackgroundingOnSocket];
}];
To keep backgrounding even when in Lock Screen, I read an answer saying that we should have something like at the end of didFinishLaunchingWithOptions but what code is in [self backgroundHandler] method?
BOOL backgroundAccepted = [[UIApplication sharedApplication]
setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
NSLog(#"background handler accepted");
return YES;
The applicationDidEnterBackground delegate method of UIApplication shows
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"=== DID ENTER BACKGROUND ===");
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)])
NSLog(#"Multitasking Supported");
else
return;
// Shall I remove my KVO observers when in background?? I guess NOT, right? :D
//[[NSNotificationCenter defaultCenter] removeObserver:self];
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
// [self askToRunMoreBackgroundTask]; This code seems to be unnecessary. I'll verify it.
}];
if (bgTask == UIBackgroundTaskInvalid)
NSLog(#"This application does not support background mode");
else
NSLog(#"Application will continue to run in background");
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
I got it working following this tutorial but looks like GCDAsyncSocket is no longer maintained so it will work only on iOS7.
http://www.objc.io/issue-5/multitasking.html
To do background file transfer under iOS 8 I am using AFNetworking library (http://afnetworking.com)
How to use NSTimer with data from NSURL pass to NSXMLParser display in TableView
I have application display data from web server by PHP gen' to XML
In my xcode i use NSURL for connect to PHP file (in web server)
and use NSXMLParser to read XML data put value to array
and final display on TableView
I want to see data in TableView live update or update every x time
I think i can use NSTimer but i don't know how i can
where i can put NSTimer to the code in xcode
In short, something like:
// Schedule a timer repeating every 2 seconds
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self.tableView
selector:#selector(reloadData)
userInfo:nil
repeats:YES];
Longer version:
You need to call -doParse from a timer, fetch data, do parsing, and reload the data.
In order not to block main thread, you must NOT call [[NSXMLParser alloc] initWithContentsOfURL:theURL] from main thread.
Instead:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithContentsOfURL:theURL];
...
// finish parsing
dispatch_async(dispatch_get_main_queue(), ^{
[tableView reloadData];
});
});
And call -doParse with a NSTimer from -viewDidLoad :
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(doParse)
userInfo:nil
repeats:YES];
Further reading:
WWDC 2012 Session 211 - Building Concurrent User Interfaces on iOS.
I have never coded an App with Push Notifications and I have a very general question.
I would like to refresh a UITableview's data (coming from a webservice) automaticaly without "pull to refresh" or any other user's interaction. Is it possible to use Push notifications to inform my app for a data change, in order to avoid polling every xx seconds wasting bandwidth and battery?
In other words, while my app runs in the foreground (maybe) I can handle the message and the user wont receive a popup but what happens otherwise?
Is there any other way to achieve the same result?
I am going to use IOS 5.0+
Thanks in Advance
You could make a server HTTP-Request which only returns something if there was a change. Then in case this response is not empty you can reload the data. The function you can call by a NSTimer.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(get) userInfo:nil repeats:YES];
and
-(void)get {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://example.com/app.php"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(![responseString isEqualToString:#""]) {
// reload
}
}
When your app is running, you can register to receive push notifications. Then it's simply a matter of implementing the method, making it update your tableview.
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
It's pretty well documented by Apple.