Не удается получить последнюю версию компонента из AppDelegate - PullRequest
0 голосов
/ 19 января 2020

Я довольно новичок в iOS разработке и вступил в должность, где мне нужно поддерживать большой существующий проект в obj- c.

У меня есть боковое меню, которое представляет собой веб-просмотр. Когда программа запускается, она делает запрос URL, чтобы проверить, есть ли более новая версия меню, и в этом случае получает последнюю версию.

Прямо сейчас, когда приложение запускается в первый раз, оно показывает старую версию. , а со второго раза и на нем показывается текущая версия.

Когда я попробовал отладку, я увидел, что метод, который сравнивает локальную и удаленную версию, получает пустое значение для удаленной версии. Насколько я понимаю, запрос url для последней версии asyn c, и поэтому код продолжает выполняться до того, как запрос вернет текущую версию.

После ответа от StackOverflow я попытался вызвать метод getDataConfiguration из viewDidLoad вместо AppDelegate, но это не сработало.

Буду признателен за любую помощь!

соответствующий код:

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { . 

...
    [DataManager getDataConfiguration:^(DataConfiguration *dataConfiguration, NSError *error) {
        [AppData sharedInstance].dataConfiguration=dataConfiguration;
        NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
        NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:dataConfiguration];
        [standardDefaults setObject:encodedObject forKey:DATA_KEY];
        [standardDefaults synchronize];
    }];

    [DataManager getProductMap:^(ProductsArray *products, NSError *error) {        
        [AppData sharedInstance].productsArray=products;
    }];

DataManager.m

+(void)getDataConfiguration:(void (^)(DataConfiguration * dataConfiguration, NSError *error))completion
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    [manager GET:[Configuration sharedInstance].infoJSONURL parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {

        DataConfiguration * dataConfiguration = [DataConfiguration modelObjectWithDictionary:responseObject];

        completion(dataConfiguration,nil);

    } failure:^(NSURLSessionTask *operation, NSError *error) {
        NSLog(@"Error: %@", error);
    }];

}

+(void)updateHtmlFiles:(void (^)(NSError *error))completion{

    float upToDateMenuVersion = [[AppData sharedInstance] dataConfiguration].general.menuVersion;
    float localMenuVersion = [self getLocalMenuVersion];
    if(upToDateMenuVersion != localMenuVersion){
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];

        NSString *url = [NSString stringWithFormat:@"%@?v=%f", [Configuration sharedInstance].menuHTMLFileURL, [[NSDate new] timeIntervalSince1970]];
        [manager GET:url parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
            NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
            NSDictionary *htmlFiles = [userDefaults dictionaryForKey:@"HTML_FILES"];
            NSMutableDictionary *mutableHtmlFiles = [NSMutableDictionary new];

            NSString *myString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
            [mutableHtmlFiles setValue:myString forKey:@"MENU"];

            [userDefaults setObject:mutableHtmlFiles forKey:@"HTML_FILES"];
            [self setLocalMenuVersion:upToDateMenuVersion];
            completion(nil);

        } failure:^(NSURLSessionTask *operation, NSError *error) {
            NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
            NSDictionary *htmlFiles = [userDefaults dictionaryForKey:@"HTML_FILES"];
            if(htmlFiles == nil){
                NSString *menuFile = [[NSBundle mainBundle] pathForResource:@"menu" ofType:@"html"];
                htmlFiles = @{@"MENU":[NSString stringWithContentsOfFile:menuFile encoding:NSUTF8StringEncoding error:nil]};
                [userDefaults setObject:htmlFiles forKey:@"HTML_FILES"];
            }
            NSLog(@"Error: %@", error);
        }];
    }
}

+(void) setLocalMenuVersion: (float) version{
    [[NSUserDefaults standardUserDefaults] setFloat:version forKey:@"menuVersion"];
}

+(float) getLocalMenuVersion {
    return [[NSUserDefaults standardUserDefaults] floatForKey:@"menuVersion"];
}

Menu.m

- (void)viewDidLoad {
    [super viewDidLoad];

    _firstLoad = YES;

...

    [self initWebView];
}

-(void) initWebView {
  if(_webView == nil){
            _webView = [[WKWebView alloc] initWithFrame:_webViewPlaceholder.frame];
              [_webView.scrollView setZoomScale:3 animated:YES];
            _webView.navigationDelegate = self;
            _webView.UIDelegate = self;
               NSString *javaScriptText = @"document.body.style.zoom = 3;";
               [_webView evaluateJavaScript:javaScriptText completionHandler:nil];

          [self.view addSubview:_webView];
            _webView.scrollView.bounces = NO;
        [self updateHtml];
        [AppData updateHeaderAndMenu:^(NSError *error){
            [self updateHtml];
        }];

        }
}

- (void)viewDidAppear:(BOOL)animated{

        _webView.frame = CGRectMake(_webViewPlaceholder.frame.origin.x,_webViewPlaceholder.frame.origin.y, _webViewPlaceholder.frame.size.width, _webViewPlaceholder.frame.size.height);

}

-(void)updateHtml{

    NSDictionary *htmlFiles = [AppData getHeaderAndMenu];
    NSString *menu = [htmlFiles objectForKey:@"MENU"];
    [_webView loadHTMLString:menu baseURL: [[NSBundle mainBundle] bundleURL]];
}

AppData.m

+(void)updateHeaderAndMenu:(void (^)(NSError *error))completion{
    [DataManager updateHtmlFiles:completion];
}

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
...
 [AppData updateHeaderAndMenu:^(NSError *error){ [self loadHeader]; }];
  _firstLoad = YES;
...

1 Ответ

0 голосов
/ 20 января 2020

У метода updateHeaderAndMenu есть блок завершения, который вызывается после завершения асинхронной операции c без ошибки.

Я предполагаю, что ViewController.m содержит ссылку на Menu? Если это так, viewDidLoad вызывает метод updateHeaderAndMenu и выполнит блок завершения (если ошибки нет). В этом блоке я уже вижу, что метод называется loadHeader. Вы могли бы позвонить туда [self.menu updateHtml];, и это, вероятно, сработало бы.

...
 [AppData updateHeaderAndMenu:^(NSError *error){
    [self loadHeader];
    // [self.menu updateHtml];
 }];
  _firstLoad = YES;
...

Я выполняю здесь некоторые предположения, но думаю, что это обновит ваше веб-представление после того, как DataManager завершит запрос http.

Редактировать: Что касается порядка исполнения. Вот разбивка:

Это определение метода в AppData +(void)updateHeaderAndMenu:(void (^)(NSError *error))completion{ [DataManager updateHtmlFiles:completion]; }

Вы можете видеть, что completion (который является параметром блока) передается в updateHtmlFiles метод в DataManager: +(void)updateHtmlFiles:(void (^)(NSError *error))completion{ ... completion(nil); ... }

В конце концов параметр завершения (который является блоком) вызывается при завершении асинхронного http-запроса 1059 *. Вы можете смотреть на блоки как на встроенные методы, которые можно передавать в качестве параметра. Google working with blocks ios, чтобы увидеть официальную документацию Apple для этого.

Таким образом, порядок выполнения:

  1. Menu, звонки updateHeaderAndMenu в AppData
  2. , который вызывает updateHtmlFiles в DataManager и передает completion
  3. http-запрос завершается и вызывает completion.
  4. содержимое блока выполняется полностью обратно в Menu, то есть: { [self loadHeader]; // [self.menu updateHtml]; }
  5. loadHeader выполняется ...

Если вы хотите получить лучший обзор того, что вызывается, вы можете использовать точки останова внутри вашего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...