2

I have a huge problem, i was testing my app in the Subway and when i'm in a super bad coverage station my app freeze for a while (like 30 sec o 1 min) in the first screen starting the app from cero, and then everything start working like a charm.

I have 2 functions that are the one responsible to look for the information in my WS (the response is a JSON) and i have set the time out of this NSURLRequest to 2.5 seconds, so if the server is a little slow for what ever reason i look for my JSON files stored in the iPhone instead of the ones that are in the server.

If i test my app with the airplane mode on, my code works like a charm and everything is read from the device, but if i have a very low coverage or i simulated it the app freeze and then works like on air plane mode.

If i add breakpoints in Xcode everything execute like always (i mean fast) and the last function that is called is viewWillAppear:.

Does anyone have similar problem? or anyone have an idea of what could be happening?

Any thought will be appreciated.

Thanks in advance.

This are the functions i use to get the JSON:

-(NSData *)getMainMenuJsonData{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([[defaults objectForKey:@"OnLine"] boolValue] ) {
        NSString *urlAsString = [NSString stringWithFormat:@"%@%@/%@/%@",[configs valueForKey:@"wsURL"], [configs valueForKey:@"clientToken"], [configs valueForKey:@"appToken"], [CommonsUtils getCommonUtil].getAppLanguage];
        NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:urlAsString] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:2.5];
        NSURLResponse * response = nil;
        NSError * error = nil;
        NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];

        plistPath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
        configs = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
        NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;

        if (statusCode == 200 && error == Nil) {
            if (error != Nil) {
                return Nil;
            } else {
                return data;
            }
        }
        else {
            return Nil;
        }
    }
    else {
        return Nil;
    }
}

-(NSData *)getSpecificJsonData:(NSString *)itemId{
    NSString *urlAsString = [NSString stringWithFormat:@"%@%@/%@/%@/%@",[configs valueForKey:@"wsURL"], [configs valueForKey:@"clientToken"], [configs valueForKey:@"appToken"], [CommonsUtils getCommonUtil].getAppLanguage, itemId];
    NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:urlAsString] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:2.5];
    NSURLResponse * response = nil;
    NSError * error = nil;
    NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];

    plistPath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
    configs = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
    NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;

    if (statusCode == 200 && error == Nil) {
        if (error != Nil) {
            return Nil;
        } else {
            return data;
        }
    }
    else {
        return Nil;
    }
}

And this is all the code of my main screen, once is loaded and viewWillAppear: is called, if i touch one of the buttons on the screen it takes a while (like 30 sec o 1 min) to execute btnAction: function:

//
//  vcMainScreen.m
//  SmartHotel
//
//  Created by GoSmart on 08/07/13.
//  Copyright (c) 2013 GoSmart. All rights reserved.
//

#import "vcMainScreen.h"
#import "Util.h"
#import "Reachability.h"
#import "CommonsUtils.h"

@interface vcMainScreen ()
@property (nonatomic) Reachability *reachabilityInfo;
@end

@implementation vcMainScreen {
    NSDictionary *dValue;
    NSData *jsonData;
    NSDictionary *dConfiguration, *configs, *languages;
    Util *util;
    BOOL ok;
    NSString *plistPath, *language;
}

@synthesize tabController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

    }
    return self;
}

- (void)viewDidLoad
{
    _reachabilityInfo = [Reachability reachabilityWithHostname:@"www.google.com"];
    [_reachabilityInfo startNotifier];

    [super viewDidLoad];
    util = [[Util alloc] crearUtil];
    [[self navigationController] setNavigationBarHidden:YES animated:NO];

    NetworkStatus internetStatus = [_reachabilityInfo currentReachabilityStatus];
    NSData *mainData = Nil;
    if (internetStatus != NotReachable)
    mainData = [util getMainMenuJsonData];

    if (mainData != Nil) {
        jsonData = mainData;
    }
    else {
        plistPath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
        configs = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
        languages = [configs valueForKey:@"Languages"];

        for (NSString * appLanguage in [NSLocale preferredLanguages])
        {
            language = [[languages valueForKey:appLanguage] objectAtIndex:0];
            if ([language isEqual:[NSNull null]]) {
                language = [[languages valueForKey:@"default"] objectAtIndex:0];
            }
            else{
                break;
            }
        }

        NSString *jsonPath = [NSString stringWithFormat:@"%@/%@.json",[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0],language];
        jsonData = [NSData dataWithContentsOfFile:jsonPath];
    }

    dConfiguration =[NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
    [self createTabBar];
    NSInteger count = 0;
    for (UIView* subView in self.view.subviews)
    {
        if ([subView isKindOfClass:[UIButton class]]) {
            UIButton *bCustom = (UIButton *)subView;
            [bCustom addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
            count ++;
        }
    }
    dValue = [[dConfiguration objectForKey:@"BackgroundImage"] objectAtIndex:0];
    _ivBackGround.image = [UIImage imageNamed:[util getBackgroundImageName:[dValue objectForKey:@"Image"] andRetrina:[dValue objectForKey:@"ImageRetina"]]];
    self.navigationItem.title = @"Home";
}

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];

    // Tracking view for analytics
    id tracker = [[GAI sharedInstance] defaultTracker];
    [tracker set:kGAIScreenName value:self.navigationItem.title];
    [tracker send:[[GAIDictionaryBuilder createAppView] build]];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillDisappear:animated];
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return UIInterfaceOrientationMaskPortrait;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)createTabBar
{   
    tabController = [self.storyboard instantiateViewControllerWithIdentifier:@"cCustomTabController"];
    dValue = [dConfiguration objectForKey:@"Buttons"];
    NSMutableArray  *aControllers = [[NSMutableArray alloc] init];
    int i = 0;
    for (NSString* sProperty in dValue) {
        NSString* d = @"Details";
        NetworkStatus internetStatus = [_reachabilityInfo currentReachabilityStatus];
        NSData *itemData = Nil;
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        if (internetStatus != NotReachable && [[defaults objectForKey:@"OnLine"] boolValue])
            itemData = [util getSpecificJsonData:[sProperty valueForKeyPath:@"Item"]];
        if(itemData != nil){
            UIStoryboard *aStoryboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:[NSBundle mainBundle]];
            UIViewController *vcCustom = [aStoryboard instantiateViewControllerWithIdentifier:[util getControllerName:[sProperty valueForKeyPath:@"ViewController"]]];
            [vcCustom setValue:itemData forKey:@"JsonData"];
            [vcCustom setValue:[sProperty valueForKeyPath:@"Item"] forKey:@"Item"];
            [vcCustom setValue:d forKey:@"Details"];
            [util saveJSON:itemData withName:[NSString stringWithFormat:@"%@%@",[sProperty valueForKeyPath:@"Item"],[CommonsUtils getCommonUtil].getAppLanguage]];
            [[vcCustom navigationController] setNavigationBarHidden:NO animated:NO];
            vcCustom.navigationItem.leftBarButtonItem = Nil;
            vcCustom.navigationItem.hidesBackButton = YES;
            UIImage *imageBtn = [UIImage imageNamed:[util getImageName:[sProperty valueForKeyPath:@"Image"] andRetrina:[sProperty valueForKeyPath:@"ImageRetina"]]];
            UIImage *imageBtnPress = [UIImage imageNamed:[util getImageName:[sProperty valueForKeyPath:@"ImageHeighlighted"] andRetrina:[sProperty valueForKeyPath:@"ImageRetinaHeighlighted"]]];
            UITabBarItem *tab = [[UITabBarItem alloc] initWithTitle:[sProperty valueForKeyPath:@"Title"] image:imageBtn selectedImage:imageBtnPress];
            UIImage * iSelected = imageBtnPress;
            iSelected = [iSelected imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
            [tab setSelectedImage:iSelected];
            tab.tag = i;
            if([[sProperty valueForKeyPath:@"Title"] isEqualToString:@"Notificaciones"])
                tab.badgeValue=[sProperty valueForKeyPath:@"Badge"];
            [vcCustom setTabBarItem:tab];
            [vcCustom setTitle:[sProperty valueForKeyPath:@"Title"]];
            UINavigationController *navigationController = [[cCustomNavigationController alloc] initWithRootViewController:vcCustom];
            navigationController.navigationBar.tintColor = [UIColor colorWithRed:36.0/255.0 green:134.0/255.0 blue:232.0/255.0 alpha:1];
            [aControllers insertObject:navigationController atIndex:i];
            i++;
        }
        else
        {
            UIStoryboard *aStoryboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:[NSBundle mainBundle]];
            UIViewController *vcCustom = [aStoryboard instantiateViewControllerWithIdentifier:[util getControllerName:[sProperty valueForKeyPath:@"ViewController"]]];
            NSNumber *val = [NSNumber numberWithInteger:i];
            NSString *nextJson = [sProperty valueForKeyPath:@"JsonConfigFile"];
            [vcCustom setValue:[sProperty valueForKeyPath:@"Item"] forKey:@"Item"];
            [vcCustom setValue:nextJson forKey:@"JsonConfigFile"];
            [vcCustom setValue:val forKey:@"MenuButtonSelectedTag"];
            [[vcCustom navigationController] setNavigationBarHidden:NO animated:NO];
            vcCustom.navigationItem.leftBarButtonItem = Nil;
            vcCustom.navigationItem.hidesBackButton = YES;
            UIImage *imageBtn = [UIImage imageNamed:[util getImageName:[sProperty valueForKeyPath:@"Image"] andRetrina:[sProperty valueForKeyPath:@"ImageRetina"]]];
            UIImage *imageBtnPress = [UIImage imageNamed:[util getImageName:[sProperty valueForKeyPath:@"ImageHeighlighted"] andRetrina:[sProperty valueForKeyPath:@"ImageRetinaHeighlighted"]]];
            UITabBarItem *tab = [[UITabBarItem alloc] initWithTitle:[sProperty valueForKeyPath:@"Title"] image:imageBtn selectedImage:imageBtnPress];
            UIImage * iSelected = imageBtnPress;
            iSelected = [iSelected imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
            [tab setSelectedImage:iSelected];
            tab.tag = i;
            if([[sProperty valueForKeyPath:@"Title"] isEqualToString:@"Notificaciones"])
                tab.badgeValue=[sProperty valueForKeyPath:@"Badge"];
            [vcCustom setTabBarItem:tab];
            [vcCustom setTitle:[sProperty valueForKeyPath:@"Title"]];
            UINavigationController *navigationController = [[cCustomNavigationController alloc] initWithRootViewController:vcCustom];
            navigationController.navigationBar.tintColor = [UIColor colorWithRed:36.0/255.0 green:134.0/255.0 blue:232.0/255.0 alpha:1];
            [aControllers insertObject:navigationController atIndex:i];
            i++;
        }


    }
    tabController.delegate = self;
    tabController.viewControllers = aControllers;
    tabController.tabBar.tintColor = [UIColor blackColor];
}

-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
    return YES;
}

- (IBAction)btnAction:(id)sender {
    UIButton *bCustom = (UIButton *)sender;

    tabController.selectedIndex = bCustom.tag;

    id<GAITracker> tracker= [[GAI sharedInstance] defaultTracker];

    [tracker send:[[GAIDictionaryBuilder createEventWithCategory: @"ui_button"
                                                          action: @"button_press"
                                                           label: [NSString stringWithFormat:@"%@-%@", self.title, [[tabController.viewControllers objectAtIndex:bCustom.tag] title]]
                                                           value: nil] build]];

    [self.navigationController pushViewController:tabController animated:YES];
}

@end

This are the setting in my iPhone:

Network settings

Stornu2
  • 2,284
  • 3
  • 27
  • 47
  • Your problem is that you're using `sendSynchronousRequest`. From the doc: "The calling thread is blocked while the asynchronous loading system performs the URL load [...]". As your calling that from the main thread, you are blocking it and the UI becomes unresponsive. This works fine on a stable and fast Internet connection because the app hangs for a few milliseconds, but on a poor network, the hang will be very noticeable. – Guillaume Algis Jan 21 '15 at 12:27
  • @GuillaumeAlgis But i don't understand why when UI response again, everything work like a charm, i call getSpecificJsonData:itemId every time a touch a button, so it can't be sendSynchronousRequest that will freeze my screen all the time, in fact when i'm in airplane mode the app became a little slow (2.5 sec) every time i touch a button, and the behavior is the expected, but on low coverage when starting the app the UI freeze and then works like when i'm on airplane mode (2,5 sec slow every time a touch a button) – Stornu2 Jan 21 '15 at 12:38
  • @GuillaumeAlgis NOTE: I have detected that sometimes the function NetworkStatus internetStatus = [_reachabilityInfo currentReachabilityStatus] returns NotReachable and some others returns ReachableViaWWAN if it is the ReachableViaWWAN it will execute sendSynchronousRequest and when it returns NotReachable it will not execute sendSynchronousRequest and on both cases the UI freeze, this is driving me crazy – Stornu2 Jan 21 '15 at 12:54

1 Answers1

2

There is no right answer to this, i was making a call in a thread to my WS in the AppDelegate that was making the UI freeze, thanks to the words of @Guillaume Algis and this i was able to find and solve my issue.

Like always thanks for all your help.

Community
  • 1
  • 1
Stornu2
  • 2,284
  • 3
  • 27
  • 47