6

Tôi hoàn toàn bối rối, đây là tình hình:Tại sao popViewController chỉ làm việc mỗi thời gian khác

ứng dụng của tôi sử dụng Vị trí khuôn khổ cốt lõi để có được vị trí hiện tại của người dùng và sau đó ping máy chủ của tôi tại TrailBehind cho địa điểm thú vị lân cận và hiển thị chúng dưới dạng danh sách. Không vấn đề gì.

Để tiết kiệm pin, tôi tắt dịch vụ GPS sau khi nhận dữ liệu từ máy chủ. Nếu người dùng di chuyển trong khi sử dụng ứng dụng và muốn danh sách mới, anh ta nhấp vào "Làm mới" trên bộ điều khiển điều hướng và dịch vụ CLLocation được kích hoạt lại, một loạt dữ liệu mới sẽ được truy xuất từ ​​máy chủ và bảng được vẽ lại.

Trong khi ứng dụng đang lấy dữ liệu từ máy chủ của tôi, tôi tải màn hình tải với hình cầu quay có nội dung "Đang tải, vui lòng đợi" và tôi ẩn thanh điều hướng để chúng không bị "quay lại".

Vì vậy, việc lấy dữ liệu ban đầu từ máy chủ sẽ hoàn hảo.

Lần đầu tiên tôi nhấn làm mới tất cả mã thực thi để có vị trí mới, ping lại máy chủ để có danh sách dữ liệu mới và cập nhật các ô. Tuy nhiên, thay vì tải chế độ xem bảng vì nó sẽ khôi phục thanh điều khiển điều hướng cho chế độ xem bảng nhưng vẫn hiển thị chế độ xem tải của tôi trong cửa sổ chính. Điều này chỉ đúng trên thiết bị, mọi thứ hoạt động hoàn toàn tốt trong trình mô phỏng.

Thời gian SECOND tôi nhấn làm mới chức năng hoạt động bình thường.

Thời gian THIRD tôi nhấn làm mới không thành công như trên.

Thời gian FOURTH tôi nhấn làm mới nó hoạt động bình thường.

Thời gian FIFTH tôi nhấn làm mới không thành công như trên.

v.v., thậm chí làm mới thành công và làm mới lẻ không thành công. Tôi bước qua tất cả các dòng mã của tôi bằng cách và tất cả mọi thứ dường như được thực hiện bình thường. Tôi thực sự tiếp tục bước qua các hướng dẫn cốt lõi và sau khi một số lượng lớn các nhấp chuột "bước qua" tôi thấy rằng xem bảng thực sự hiển thị trên màn hình tại một số điểm trong CFRunLoopRunSpecific, nhưng sau đó tôi nhấp "tiếp tục" và xem tải của tôi đã qua màn hình.

Tôi hoàn toàn bối rối. Hãy giúp tôi!! Rất cám ơn trước vì sự thấu hiểu của bạn.

Video of the strange behavior:

Mã liên quan:

RootViewControllerMethods (Đây là quan điểm cơ sở cho dự án này TableView)

- (void)viewDidLoad { 
    //Start the Current Location controller as soon as the program starts. The Controller calls delegate methods 
    //that will update the list and refresh 
    [MyCLController sharedInstance].delegate = self; 
    [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    [super viewDidLoad]; 
} 



- (void)updateClicked { 
    //When the location is successfully updated the UpdateCells method will stop the CL manager from updating, so when we want to update the location 
    //all we have to do is start it up again. I hope. 
    [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    //LV is a class object which is of type UIViewController and contains my spinning globe/loading view. 
} 



-(void)updateCells { 
    //When the Core Location controller has updated its location it calls this metod. The method sends a request for a JSON dictionary 
    //to trailbehind and stores the response in the class variable jsonArray. reloadData is then called which causes the table to 
    //re-initialize the table with the new data in jsonArray and display it on the screen. 

    [[MyCLController sharedInstance].locationManager stopUpdatingLocation]; 

    if(self.navigationController.visibleViewController != self) { 
     self.urlString = [NSString stringWithFormat:@"http://www.trailbehind.com/iphone/nodes/%@/%@/2/10",self.lat,self.lon]; 
     NSURL *jsonURL = [NSURL URLWithString:self.urlString]; 
     NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL]; 
     NSLog(@"JsonData = %@ \n", jsonURL); 
     self.jsonArray = [jsonData JSONValue]; 
     [self.tableView reloadData]; 
     [self.navigationController popToRootViewControllerAnimated:YES]; 
     [jsonData release]; 
    } 
} 

CLController Phương pháp: Về cơ bản chỉ gửi tất cả các dữ liệu thẳng trở lại RootViewController

// Called when the location is updated 
- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation 
{ 
    NSLog(@"New Location: %@ \n", newLocation); 
    NSLog(@"Old Location: %@ \n", oldLocation); 
    @synchronized(self) { 
     NSNumber *lat = [[[NSNumber alloc] init] autorelease]; 
     NSNumber *lon = [[[NSNumber alloc] init] autorelease]; 
     lat = [NSNumber numberWithFloat:newLocation.coordinate.latitude]; 
     lon = [NSNumber numberWithFloat:newLocation.coordinate.longitude]; 
     [self.delegate noteLat:lat]; 
     [self.delegate noteLon:lon]; 
     [self.delegate noteNewLocation:newLocation]; 
     [self.delegate updateCells]; 
    } 
} 
+0

Bạn đã từng bước qua các phương pháp này trong trình gỡ rối chưa? Chạy các công cụ trên đó để xem việc tạo/xóa đối tượng có phải là những gì bạn mong đợi không? Xin lỗi nếu tôi xúc phạm trí thông minh của bạn, nhưng vì tôi không thấy vấn đề từ cái nhìn nhanh, điều tiếp theo tôi muốn làm là bắt đầu bước qua ... – mikeh

+0

Cửa sổ bật lên có xuất hiện nếu bạn thoát ứng dụng không? Có vẻ như bạn không rời khỏi ứng dụng đủ thời gian để sửa chữa GPS trong video. Thử đặt các điểm ngắt trong phương thức locationManager. –

Trả lời

0

Bạn có thể thử và gỡ lỗi ứng dụng của bạn để xem nơi điều khiển đi khi gọi updateCells không? Dường như dường như không có gì sai với ứng dụng.

Đảm bảo rằng không có cảnh báo bộ nhớ trong khi bạn đang ở trong lớp LoadingViewController. Nếu có một cảnh báo bộ nhớ và khung nhìn RootViewController của bạn đang được phát hành, thì viewDidLoad sẽ được gọi lại khi bạn thực hiện một pop to RootViewController.

Giữ các điểm ngắt trong chế độ xemDidLoad và updateCells. Bạn có chắc bạn không gọi LoadingViewController ở bất kỳ nơi nào khác không?

+0

Tôi đã đặt điểm ngắt trong cả hai chức năng đó và viewDidLoad không được gọi khi màn hình tải được bật lên. Cũng không có hàm didRecieveMemoryError nào của tôi được gọi. Sau khi updateCells được gọi là kiểm soát trả về cho ngăn xếp cốt lõi, và tôi nghĩ rằng một cái gì đó trong đó có thể gây rối với tôi. –

1

Ý nghĩ đầu tiên là bạn có thể không muốn gửi startUpdatingLocation đến CLLocationManager cho đến khi sau khi bạn đã đẩy chế độ xem tải. Thông thường, trình quản lý vị trí đầu tiên: didUpdateToLocation: fromLocation: thông báo sẽ xuất hiện ngay lập tức với dữ liệu GPS được lưu trong bộ nhớ cache. Điều này chỉ quan trọng nếu bạn đang hành động trên mọi thư và không lọc dữ liệu GPS như được hiển thị trong mã mẫu của bạn tại đây. Tuy nhiên, điều này sẽ không gây ra tình huống mà bạn đã mô tả - điều này sẽ khiến màn hình tải bị kẹt.

Tôi đã trải nghiệm hành vi kỳ lạ tương tự như thế này trong một tình huống khác khi tôi cố gắng bật trình điều khiển chế độ xem gốc khi chuyển sang tab khác và cuộc gọi không được thực hiện ở đúng vị trí. Tôi tin rằng popToRootViewController đã được gọi hai lần cho tôi. Nghi ngờ của tôi là chế độ xem tải của bạn đang bị đẩy hai lần hoặc xuất hiện hai lần.

Tôi khuyên bạn nên triển khai -viewWillAppear :, -viewDidAppear :, -viewWillDisappear: and -viewDidDisappear: với ghi nhật ký tối thiểu trong tệp LoadingViewController của bạn.

- (void)viewWillAppear:(BOOL)animated { 
    NSLog(@"[%@ viewWillAppear:%d]", [self class], animated); 
    [super viewWillAppear:animated]; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    NSLog(@"[%@ viewDidAppear:%d]", [self class], animated); 
    [super viewDidAppear:animated]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    NSLog(@"[%@ viewWillDisappear:%d]", [self class], animated); 
    [super viewWillDisappear:animated]; 
} 

- (void)viewDidDisappear:(BOOL)animated { 
    NSLog(@"[%@ viewDidDisappear:%d]", [self class], animated); 
    [super viewDidDisappear:animated]; 
} 

Sau đó, chạy thử nghiệm trên thiết bị để xem liệu chúng có được gửi đến bộ điều khiển chế độ xem của bạn hay không và tần suất. Bạn có thể thêm một số lần đăng nhập vào -updateNhấp để hiển thị các thao tác nhấn đúp.

Một ý nghĩ khác, trong khi khối @synchronized của bạn là một ý tưởng hay, nó sẽ chỉ giữ các chủ đề khác thực hiện các câu lệnh đó cho đến khi luồng đầu tiên thoát khỏi khối. Tôi khuyên bạn nên di chuyển thông báo -stopUpdatingLocation để là câu lệnh đầu tiên bên trong khối @synchronized đó. Bằng cách đó, một khi bạn quyết định hành động trên một số dữ liệu GPS mới, bạn ngay lập tức yêu cầu CLLocationManager ngừng gửi dữ liệu mới.

0

Vì vậy, tôi chưa bao giờ làm việc này. Tôi quan sát hành vi này trên thiết bị chỉ mỗi khi tôi gọi popViewController lập trình thay vì cho phép nút quay lại mặc định trên bộ điều khiển điều hướng để thực hiện lệnh popping.

Cách giải quyết của tôi là tạo chế độ xem tải tùy chỉnh và lật màn hình sang chế độ xem đó mỗi lần có sự chậm trễ do truy cập internet. Phương pháp của tôi có một biến boolean có hoặc không - có chuyển sang màn hình tải và không có thiết bị chuyển mạch trở lại chế độ xem bình thường. Dưới đây là các mã:

- (void)switchViewsToLoading:(BOOL)loading { 
// Start the Animation Block 
CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft forView:self.tableView cache:YES]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:.75]; 

// Animations 
if(loading) { 
    if (lv == nil) { lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; } 
    [self.view addSubview:lv.view]; 
    [self.view sendSubviewToBack:self.tableView]; 
    self.title = @"TrailBehind"; 
} 
else { 
    [lv.view removeFromSuperview]; 

} 
// Commit Animation Block 
[UIView commitAnimations]; 
//It looks kind of dumb to animate the nav bar buttons, so set those here 
if(loading) { 
    self.navigationItem.rightBarButtonItem = nil; 
    self.navigationItem.leftBarButtonItem = nil; 
    self.title = @"TrailBehind"; 
} 
else { 
    UIBarButtonItem *feedback = [[UIBarButtonItem alloc] initWithTitle:@"Feedback" style:UIBarButtonItemStylePlain target:self action:@selector(feedbackClicked)]; 
    self.navigationItem.rightBarButtonItem = feedback; 
    UIBarButtonItem *update = [[UIBarButtonItem alloc] initWithTitle:@"Move Me" style:UIBarButtonItemStylePlain target:self action:@selector(updateClicked)]; 
    self.navigationItem.leftBarButtonItem = update; 
    [feedback release]; 
    [update release]; 
} 

}

0

Nhìn vào mã ban đầu của bạn, tôi nghi ngờ khối này rất nhiều:

- (void)viewDidLoad { 
    ... 
    lv = [[LoadingViewController alloc] initWithNibName:@"Loading" bundle:nil]; 
    [self.navigationController pushViewController:lv animated:YES]; 
    [super viewDidLoad]; 
} 

viewDidLoad được gọi mỗi khi NIB được nạp, có thể xảy ra nhiều thời gian, đặc biệt là nếu bạn chạy bộ nhớ thấp (một cái gì đó có vẻ như có khả năng đưa ra nhận xét của bạn rằng nó chỉ xảy ra trên thiết bị). Tôi khuyên bạn nên triển khai -didReciveMemoryWarning và sau khi gọi điện cho siêu, ít nhất hãy in nhật ký để bạn có thể xem liệu điều đó có xảy ra với bạn hay không.

Điều làm phiền tôi về mã ở trên là bạn gần như chắc chắn bị rò rỉ lv, có nghĩa là có thể có số lượng ngày càng tăng là LoadingViewControllers chạy xung quanh. Bạn nói đó là biến lớp. Bạn có thực sự có nghĩa là nó là một biến thể hiện? ivars nên luôn sử dụng accessors (self.lv hoặc [self lv] thay vì lv). Không trực tiếp gán cho họ; bạn sẽ hầu như luôn luôn làm điều đó sai (như bạn có khả năng đồng ở đây).

0

Tôi gặp vấn đề này khi tìm kiếm chính xác cùng một vấn đề, vì vậy trong khi tôi chắc chắn bạn đã giải quyết được sự cố của mình, tôi đã tìm ra giải pháp của mình trong trường hợp người khác chạy qua ...

Lỗi này dường như xảy ra khi bạn gán hai IBActions cho cùng một UIButton trong trình tạo giao diện. Nó bật ra rằng nút tôi sử dụng để đẩy bộ điều khiển xem vào ngăn xếp được gán cho hai IBActions, và mỗi cái đã đẩy một bộ điều khiển khác vào ngăn xếp của navigationController (mặc dù bạn sẽ chỉ thấy một trong số chúng - có lẽ là cuối cùng một cái được gọi). Vì vậy, dù sao đi nữa, nhấn nút quay lại ở chế độ xem trên cùng không thực sự loại bỏ nó (hoặc có thể nó loại bỏ bộ điều khiển thứ hai, không nhìn thấy) và bạn phải nhấn hai lần để quay lại.

Dù sao, hãy kiểm tra các nút của bạn và đảm bảo rằng chúng chỉ được gán cho một IBAction. Điều đó đã sửa nó cho tôi.