ios6 cachedResponseForRequest blocks sendSynchronousRequest - ios

This does not occur in Xcode 4.4, but with 4.5, using ios6 simulator or real device, the call to sendSynchronousRequest does not return until timeout if called from within cachedResponseForRequest.
Likewise, a loop that uses sendAsynchronousRequest and spins (for 10 seconds checking every 0.05 seconds for the completion), finishes the loop (10 seconds passed), but never completes the request (if called from within cachedResponseForRequest).
In Xcode 4.4 (emulating ios5), this does not occur.
Any ideas?

just use the method "sendAsynchronousRequest".
here is my solution and it works like a charm.
[NSURLConnection sendAsynchronousRequest:newRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data,NSError *error){
NSLog(#"--- caching ---");
if (error) {
NSLog(#"%#", error);
NSLog(#"not cached: %#", absoluteString);
}
NSString *filename = [self sha1:absoluteString];
NSString *path = [cacheDirectory stringByAppendingPathComponent:filename];
NSFileManager *fileManager = [[NSFileManager alloc] init];
[fileManager createFileAtPath:path contents:data attributes:nil];
[fileManager release];
NSURLResponse *newResponse = [[NSURLResponse alloc] initWithURL:response.URL MIMEType:response.MIMEType expectedContentLength:data.length textEncodingName:nil];
NSDictionary *responseInfo = [NSDictionary dictionaryWithObjectsAndKeys:filename, #"filename", newResponse.MIMEType, #"MIMEType", nil];
[responsesInfo setObject:responseInfo forKey:absoluteString];
cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:newResponse data:data];
[newResponse release];
[cachedResponses setObject:cachedResponse forKey:absoluteString];
[cachedResponse release];
}];
because it's only available in iOS5.0 and later. you may need to check the ios version first.

Related

iPhone sdk : Open Default Message tones list

In my application , i want to set default system message tones for upcoming message settings. How can i open default device alertTones list.
I have tried following code, but its not returning any sound.
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *directoryURL = [NSURL URLWithString:#"/System/Library/Audio/UISounds"];
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey];
NSDirectoryEnumerator *enumerator = [fileManager
enumeratorAtURL:directoryURL
includingPropertiesForKeys:keys
options:0
errorHandler:^(NSURL *url, NSError *error) {
// Handle the error.
// Return YES if the enumeration should continue after the error.
return YES;
}];
for (NSURL *url in enumerator) {
NSError *error;
NSNumber *isDirectory = nil;
if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) {
// handle error
}
else if (! [isDirectory boolValue]) {
[audioFileList addObject:url];
}
}
Please Help.
Checked this link https://github.com/TUNER88/iOSSystemSoundsLibrary. I think are you using this reference code and its working I have tested in the iPhone. I think you were testing in the iPhone Simulator. its not working in the simulator. So, Test in the Device its working fine

NSString *latestVersionString

I am currently using this in my Xcode 5 application and I can't seem to get it working
NSString *bundleVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
NSString *latestVersionString = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/version.txt"] encoding:NSUTF8StringEncoding error:nil];
#import NSString+compareToVersion.h
if ([bundleVersion isOlderThanVersion:latestVersionString]) {
// show a blocking modal view, with a button to link to the app store}
First, I do not recommend using synchronous network calls, regardless of how small the .txt file may be. You can try this for your code: Make sure to include <UIAlertViewDelegate> in your .h file first.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[UIApplication sharedApplication]beginIgnoringInteractionEvents];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:#"http://mywebsite.com/version.txt"]];
request.timeoutInterval = 10.0;
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (data)
{
NSString *bundleVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
NSString *latestVersionString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (![bundleVersion isEqualToString:latestVersionString])
{
// The two strings are not equal, dispatch to the UI thread and show a UIAlertView
dispatch_async(dispatch_get_main_queue(), ^
{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Update App!"
message:#"Please download the newer version available first on the App Store!"
delegate:self cancelButtonTitle:#"App Store"
otherButtonTitles:nil];
[alertView show];
[[UIApplication sharedApplication]endIgnoringInteractionEvents];
});
}
else
{
// Up to date; no new version is available, proceed to game play routines
[[UIApplication sharedApplication]endIgnoringInteractionEvents];
}
}
else
{
// No internet, or there is no data at the url, show error
// Uncomment below line if you want the user to interact with app again
// [[UIApplication sharedApplication]endIgnoringInteractionEvents];
}
}];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:#"Your App Store app link here"]];
}
First, check the value of latestVersionString in the debugger. Make sure it is the value you want it to be (and not e.g. nil). Also, declare an NSError * to capture any error that arises from trying to initialise a string from an HTTP URL (consider the case where there may be no internet connection, or temporary routing or DNS issue etc.).
NSError *error = nil;
NSString *latestVersionString = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/version.txt"] encoding:NSUTF8StringEncoding error:&error];
if (error != nil)
{
// figure out what went wrong based on the error
}
else
{
// check latestVersionString contains something valid and then compare
// with bundleVersion.
}
If both bundleVersion and latestVersionString contain what you expect, then the issue may be in the isOlderThanVersion: method.

app segues before my data is populated causing the table view no to populate

I have an app that queries iTunes. When the data returns I want to segue from the search screen to a tableview that displays the songs.
My problem: I'm getting the data back but my segue is happening before the data is back so the numberOfRowsInSection count is still 0 and my app just stops. I don't understand why the conditional doesn't execute before my performselector method.
Here's my code:
- (IBAction)searchForTrack:(id)sender {
NSString *trackName = [[NSString alloc]init];
tracks = [[NSMutableArray alloc]init];
trackName = _searchText.text;
NSURLSession *session = [NSURLSession sharedSession];
NSString *appURL = [NSString stringWithFormat:#"https://itunes.apple.com/search?term=%#",trackName];
//NSLog(appURL);
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:appURL] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary *jsonDict= [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
//NSLog(#"%#", jsonDict);
if (jsonDict)
{
for (id trackDict in [jsonDict objectForKey:#"results"]){
Track *track = [[Track alloc] initWithJSONDictionary:trackDict];
NSString *trackName = [trackDict objectForKey:#"trackName"];
NSString *artistName = [trackDict objectForKey:#"artistName"];
NSString *trackPrice = [trackDict objectForKey:#"trackPrice"];
NSString *releaseDate = [trackDict objectForKey:#"releaseDate"];
NSString *primaryGenreName = [trackDict objectForKey:#"primaryGenreName"];
[tracks addObject:track];
}
}
else
{
NSLog(#"No Darn Tracks Were Found or Something else is screwed up");
}
}];
[dataTask resume];
[self performSelector:#selector(switchToTableview)];
}
You don't show the full code, but the
}];
give's the clue that the conditional code is being executed in a block.
Your code is not executing in a one-line-at-a-time manner due to the block which is probably the cause of the problem, but you need to post all the code to confirm and to suggest the best solution (which will be remove the block, or add a completion part to the block).

Asynchronous request returning nil

i've made following Asynchronous request, the problem is that its empty i've tried in the bottom NSLog the fixtures where its empty. I've checked that the nsstring home, away, league and so on returns values and it does. How come the values are not added to the fixtures NSMutableArray
[ProgressHUD show:#"Loading..."];
NSURL *url = [NSURL URLWithString:#"API_URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
jsonResult = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
int subObjects = ((NSArray *)jsonResult[#"match"]).count;
for (int i = 0; i <= subObjects-1; i++) {
NSString *date = [NSString stringWithFormat:#"%# %#",[[[jsonResult valueForKey:#"match"] valueForKey:#"playdate"] objectAtIndex:i], [[[jsonResult valueForKey:#"match"] valueForKey:#"time"] objectAtIndex:i]];
NSString *identifier = [[NSLocale currentLocale] localeIdentifier];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone: [NSTimeZone timeZoneWithName:#"US/Arizona"]];
[df setLocale:[NSLocale localeWithLocaleIdentifier:identifier]];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *myDate = [df dateFromString:[NSString stringWithFormat:#"%#", date]];
NSArray *items = [[NSString stringWithFormat:#"%#", myDate] componentsSeparatedByString:#" "];
NSString *home = [[[jsonResult valueForKey:#"match"] valueForKey:#"hometeam"] objectAtIndex:i];
NSString *away = [[[jsonResult valueForKey:#"match"] valueForKey:#"awayteam"] objectAtIndex:i];
NSString *league = [[[jsonResult valueForKey:#"match"] valueForKey:#"league"] objectAtIndex:i];
[fixtures addObject:
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
items[0], #"date",
items[1], #"time",
home, #"home",
away, #"away",
league, #"league",
nil]];
[sections addObject:
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
items[0], #"date",
nil]];
}
}
];
[self.theTableView reloadData];
[ProgressHUD dismiss];
NSLog(#"%#", fixtures);
The problem is that the request is an asynchronous function
If the function is asynchronous, the function will create another thread and return immediately to execute the next line after the one that invoked the asynchronous function. Meanwhile the new thread will execute some code and, eventually execute the block passed as parameter, and finally the thread is killed and doesn't exist any more.
This means that
NSLog(#"%#", fixtures);
will most likely be executed before the sendAsynchronousRequest has finished it's job, that's why it is returning nil.
Everything you need to do to process the downloaded information should happen inside the completionHandler block, including the call to [self.theTableView reloadData];
It is a non-blocking operation. It means that by calling this method it returns immediatelly while the actual request is performing somewhere in background and then calls the handler block on queue specified in queue parameter.
You should reload tableview from the completion-handler block.
// 1 before request
NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
// 3 request completed
// some processing
...
[self.theTableView reloadData];
[ProgressHUD dismiss];
}
// 2 immediate return
update
Although you passing the main queue as queue parameter the handler block will be performed on next run loop iteration after you reloading table and logging the values.
// current run loop iteration
NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
// next run loop iteration
}
// current run loop iteration
if(!fixtures) {
fixtures = [[NSMutableArray alloc] init];
}
[fixtures addObject:#{
#"date": items[0],
#"time": items[1],
#"home": home,
#"away": away,
#"league": league
}];
if(!sections) {
sections = [[NSMutableArray alloc] init];
}
[sections addObject:#{
#"date": items[0]
}];
[self.theTableView reloadData];
[ProgressHUD dismiss];
NSLog(#"%#", fixtures);

check if file has been updated on server

In my application and at startup I check if databases has been changed on server with the copy stored locally. I'm using a synchronous request to the server and I'm doing a check based on the last modified date time fields in the HTTP response
If the last modified data time of the file on the server is > last modified date time of the local file I ask user if he would like to update the database, if he accepts I download the database.
I'm using my machine as server but the problem when I shutdown my machine, the application crash at startup
Thanks for you help
You will find below my code
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// check connectivity
if ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == NotReachable) {
[self displayConenctivityAlert];
}else{
[self checkDatabases];
}
}
- (void) checkDatabases {
bool res = [self fileUpdated];
if (res){
// Ask user if he would like to update the databases
}
}
-(void) displayConenctivityAlert{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:[TSLanguageManager localizedString:#"NO_CONNECTED"] delegate:self cancelButtonTitle:[TSLanguageManager localizedString:#"OK"] otherButtonTitles:nil];
[alert show];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Error HTTP ...");
}
- (BOOL)fileUpdated {
NSString *urlString = #"http://192.168.0.10:8888/fuel/stations.db";
NSLog(#"Downloading HTTP header from: %#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
//store locally data into the resource folder.
NSString *documentsDirectory = [Utility documentsPath];
NSString *cachedPath = [documentsDirectory stringByAppendingPathComponent:#"stations.db"];
NSLog(#"Local URL / %#", cachedPath);
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL downloadFromServer = NO;
NSString *lastModifiedString = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error: NULL];
if ([response respondsToSelector:#selector(allHeaderFields)]) {
lastModifiedString = [[response allHeaderFields] objectForKey:#"Last-Modified"];
}
NSDate *lastModifiedServer = nil;
#try {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateFormat = #"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
df.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
df.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
lastModifiedServer = [df dateFromString:lastModifiedString];
}
#catch (NSException * e) {
NSLog(#"Error parsing last modified date: %# - %#", lastModifiedString, [e description]);
}
NSLog(#"lastModifiedServer: %#", lastModifiedServer);
NSDate *lastModifiedLocal = nil;
if ([fileManager fileExistsAtPath:cachedPath]) {
NSError *error = nil;
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:cachedPath error:&error];
if (error) {
NSLog(#"Error reading file attributes for: %# - %#", cachedPath, [error localizedDescription]);
}
lastModifiedLocal = [fileAttributes fileModificationDate];
NSLog(#"lastModifiedLocal : %#", lastModifiedLocal);
}
// Download file from server if we don't have a local file
if (!lastModifiedLocal) {
downloadFromServer = YES;
}
// Download file from server if the server modified timestamp is later than the local modified timestamp
if ([lastModifiedLocal laterDate:lastModifiedServer] == lastModifiedServer) {
downloadFromServer = YES;
}
return downloadFromServer;
}
#end
Your app is crashing because it is taking too long to complete didFinishLaunching the system watchdog kills your app. This is because you are making a synchronous http request in viewDidLoad of your root view controller, which must be completed before you can finish launching. You can resolve this issue multiple ways, either do your HTTP request asynchronously by calling sendAsynchronousRequest:queue:completionHandler on your NSURLConnection. The other option is to move this code out of your launching pipeline, perhaps by moving the code to viewDidAppear of your view controller. This has the side effect of performing the check on every return to the view, not just the initial load.
In short, doing a synchronous HTTP request is a big no no because your UI will hang until the request is complete. In this case it's especially bad because you're forcing your launch to be delayed until the request is complete, which is causing it to fail when the server is down.
Problem solved
I'm using now
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
}
instead of
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error: NULL];

Resources