2014-11-01 156 views
1

我在Rails/Heroku後端的iOS應用程序中看到了奇怪的行爲。我會盡量給予儘可能多的細節。希望有人能指出一些可能出現問題的地方。發生多個POST請求

我寫了一個使用XCode 5的iOS 7應用程序,用戶可以登錄併發布新文章和評論。我正在使用AFNetworking庫與我的後端服務器進行通信(Rails 4,Heroku & Postgres)。我POST和GET的JSON格式,所以我利用AFJSONRequsetOperation來處理通信。

我所有的POST的使用這種方法:

- (void) Post:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success 
     :(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure 


// allocate a reachability object 
Reachability* reach = [Reachability reachabilityWithHostname:@"www.google.com"]; 


reach.unreachableBlock = ^(Reachability*reach) 
{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject]; 
     [HUD flashMessage :@"Whoops" :@"No internet connection" :window]; 
    }); 

    failure(nil, nil, nil, nil); 
}; 

reach.reachableBlock = ^(Reachability*reach) 
{ 

    // prepare base URL and calculate signature 
    // Something like: https://myapp.herokuapp.com 
    NSURL *url = [NSURL URLWithString:BasePath]; 

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 
    [httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
    [httpClient setDefaultHeader:@"Accept" value:@"application/json"]; 

    // Generates the POST URL 
    // Something like: https://myapp.herokuapp.com/api/v1/articles.json 
    NSString *basePath = [self GetPostURL]; 

    NSLog(@"Post %@ With parameters: %@", basePath, Parameters); 

    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:basePath parameters:Parameters]; 

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:success failure:failure]; 

    [operation start]; 
}; 


[reach startNotifier]; 

}

我做了一些測試,在我的iPhone 5.查看的一個實現代碼如下文章列表,查看在詳細查看文章的詳細信息然後用另一個tableview查看和添加註釋。我做了很多測試,發現沒有問題。最終我看到有3條完全相同的評論。我認爲我必須雙擊「添加」按鈕,以便禁用按鈕。因爲幾乎不可能重新創建,所以我沒有想到更多。

我已將手機更新到iOS 8,並更新了我的XCode和SDK以反映此情況。 我把應用程序放在我的朋友手機上(iOS 8 & iPhone 5 C)。她用了一天沒有看到任何問題。她查看了文章,評論並添加了自己的內容,沒有任何問題。

今天是一個不同的故事。首先,有點背景信息。當您打開應用程序時 - 我刷新文章列表,以便應用程序通常顯示文章的舊列表,然後出現加載圖標,tableview閃爍並顯示最新的文章。

當她今天打開應用程序 - 它閃現多次,它看起來像10左右。當桌面出現時,她昨天發佈的文章出現了兩次。確切的文章(標題,說明,經緯度,圖片)出現了兩次,但有不同的時間戳。

我以爲應用程序在她的手機上播放,所以我檢查了後端。它有兩個單獨的文章,不同的ID和時間戳,但另有確切的副本。

看着日誌,有她的帳戶20/30 GET請求。這似乎與開幕後的閃光相符。它多次更新tableview。

然後日誌顯示一個POST請求,其中包含她在前一天發佈的所有參數。就好像她今天實際上發佈了完全相同的文章 - 但顯然她沒有。

有沒有人見過這種事情?

我能想到的唯一的事情是:

  • 的添加項目視圖控制器的初始後之後都沒有被破壞並以某種方式作出積極的一次。我推測ARC會處理所有這些?
  • 也許AFNetworking庫不會被刷新並認爲需要重新發布?儘管將近24小時後。
  • 庫上是否有請求批處理操作?也許這可能是一個問題?
  • 發佈時我使用'dispatch_get_global_queue'。這個可以嗎?
  • 成功添加文章後,我使用下面的代碼再次移動到列表。也許有一個問題,我不知道?

ArticleListViewController *articleList = (ArticleListViewController *)[self.storyboard instantiateInitialViewController]; articleList.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; [self articleList animated:YES completion:nil];

我很茫然試圖複製,即使它,更不要說解決它。 我假設我正確地將手指指向應用程序?它似乎不是Heroku/rails的問題。

任何幫助將不勝感激。

更新

我只是有這個問題再次。 我昨天做了一些測試,增加了3篇文章。一切按預期工作。我偶爾會每隔幾個小時進入應用程序,以確保一切正常。我剛剛打開應用程序,它開始閃爍/閃爍。它用昨天發佈的一篇新文章更新了名單。我什麼也沒做,並且再次閃爍,並且再次添加了相同的文章(所以這2個重複與今天created_at日期)。我繼續無所事事,幾秒鐘後,我昨天添加的其他兩篇文章已經更新。一篇文章增加了3次,一篇文章增加了2倍,一篇文章剛剛複製了一次。這是奇怪的行爲。

難道會有某種形式的全局變量或保留所有數據的東西嗎?也許控制器沒有完全移除?

布賴恩

+0

是否職時間來自iPhone的服務器?如果用戶在帖子完成之前完成應用程序,會發生什麼情況,下次啓動時是否會重試? – zaph 2014-11-01 18:10:52

+0

嗨Zaph。每個GET/POST請求都有一個從iPhone追加的時間戳。每篇文章都有自己的時間戳,db中的'created_at'列。我沒有編寫任何代碼在下次啓動時重試,除非庫/ iOS爲您處理?而且,在這種情況下,POST完全完成 - 沒有問題,用戶也沒有退出。 – 2014-11-01 18:50:39

+0

你如何處理iPhone上不成功的POST? – zaph 2014-11-01 19:30:32

回答

2

經過無盡的測試。我發現了這個問題。

重複POST(s)隨機發生。當它發生時,它似乎只發生1%的時間,有時5分鐘後,有時一天後。

我最終發現它與從3G切換到WiFi有關。 在3G上添加文章,然後更改爲WiFi會導致重複。

問題是在我上面的代碼中的可達性塊。 我啓動可達性通知程序並設置兩個可達和不可達的塊。 當手機改變可達性狀態時,這些塊被擊中。因此,從3G移動到Wifi再次觸及可到達的塊,導致重複的POST。

一個簡單的解決方法是調用下面的線在每個塊的開始,以防止進一步的更新:

[reach stopNotifier]; 

或者,實現可達性,如:

-(BOOL)reachable { 
    Reachability *r = [Reachability reachabilityWithHostName:@"www.google.com"]; 
    NetworkStatus internetStatus = [r currentReachabilityStatus]; 
    if(internetStatus == NotReachable) { 
     return NO; 
} 
    return YES; 
} 

// In POST method 
if([self reachable]) 
{ 
    // Do POST 
}else{ 
    // No connection 
}