Элементы управления в ViewController теряют свое состояние после предупреждения о памяти при выключенном экране

Ситуация очень похожа на описанную в это мой другой вопрос, за исключением того, что делегирование работает нормально. Я предоставляю более подробную информацию о моем коде. Я просто вырезаю ненужные/тривиальные части.

ReportScreen.h

@interface ReportScreen : UIViewController <UIImagePickerControllerDelegate, UITextViewDelegate, MBProgressHUDDelegate, SoapDelegate, MapLocationChoiceDelegate>
// ...
@property (nonatomic, retain) MKPointAnnotation *annotation;
@property (nonatomic, retain) IBOutlet UITextView *textView;
@property (nonatomic, retain) IBOutlet UIButton *cameraButton;
@property (nonatomic, retain) IBOutlet UIButton *libraryButton;
@property (nonatomic, retain) IBOutlet UIButton *locationButton;
@property (nonatomic, retain) IBOutlet UIButton *sendButton;

@end

ReportScreen.m

@implementation ReportScreen

@synthesize annotation;
@synthesize textView;
@synthesize cameraButton;
@synthesize libraryButton;
@synthesize locationButton;
@synthesize sendButton;

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Here I used to store the VC's state to a file but it shouldn't be needed now that I'm assigning it as delegate and said delegate seems to still be there even after a memory warning.
}

- (void)viewDidLoad {
    [super viewDidLoad];

    placeholderText = @"Tell us what's wrong…";
    textView.text = placeholderText;
    self.annotation = nil;
    [self isReadyToSubmit];

    hud = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
    [self.navigationController.view addSubview:hud];
    hud.delegate = self;
    hud.labelText = @"Invio in corso…";
    hud.dimBackground = YES;
}

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

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    // Here I used to restore the state of the VC from file but… y'know.
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self isReadyToSubmit];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"goToMap"]) {
        MapScreen *vc = (MapScreen *)segue.destinationViewController;

// HERE's the magic
        vc.mapLocationChoiceDelegate = self;
// MAGIC ends

        if(self.annotation != nil) {
            vc.annotations = [[NSMutableArray alloc] init];
            [vc.annotations addObject:self.annotation];
        }
    }
}

- (BOOL)isReadyToSubmit {
    if(self.annotation != nil) {
        locationButton.highlighted = YES;
    }
    if(![textView.text isEqualToString:placeholderText] && self.annotation != nil) {
        [sendButton setEnabled:YES];
    } else {
        [sendButton setEnabled:NO];
    }
    return [sendButton isEnabled];
}

- (void)textViewDidBeginEditing:(UITextView *)theTextView {
    if([theTextView.text isEqualToString:placeholderText]) {
        theTextView.text = @"";
    }
    UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(didFinishEditing:)];
    [self.navigationItem setRightBarButtonItem:done animated:YES];
}

- (void)textViewDidEndEditing:(UITextView *)theTextView {
    if([theTextView.text isEqualToString:@""]) {
        theTextView.text = placeholderText;
    }
    [self isReadyToSubmit];
}

- (void)didFinishEditing:(id)sender {
    [self.navigationItem setRightBarButtonItem:nil animated:YES];
    [self.textView resignFirstResponder];
}

// THIS is my delegate protocol's method
- (void)locationChosen:(MKPointAnnotation *)theAnnotation {
    self.annotation = theAnnotation;
    NSLog(@"R: %@", textView.text);
}

@end

MapScreen.h

@protocol MapLocationChoiceDelegate <NSObject>
- (void)locationChosen:(MKPointAnnotation *)annotation;
@end

// ---

@interface MapScreen : UIViewController <MKMapViewDelegate>

- (void)handleLongPress:(id)sender;

@property (nonatomic, retain) NSMutableArray *annotations;
@property (nonatomic, retain) IBOutlet MKMapView *mapView;

@property (weak) id<MapLocationChoiceDelegate> mapLocationChoiceDelegate;

@end

MapScreen.m

@implementation MapScreen

@synthesize annotations;
@synthesize mapView;
@synthesize mapLocationChoiceDelegate;

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidLoad {
    [super viewDidLoad];

    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    lpgr.minimumPressDuration = 1.0;
    [self.mapView addGestureRecognizer:lpgr];

    [mapView addAnnotations:self.annotations];
}

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


#pragma mark - Map handling

- (void)handleLongPress:(id)sender {
    if(![sender isKindOfClass:[UILongPressGestureRecognizer class]]) {
        return;
    }

    UILongPressGestureRecognizer *gr = (UILongPressGestureRecognizer *)sender;
    if (gr.state != UIGestureRecognizerStateBegan) {
        return;
    }

    CGPoint touchPoint = [gr locationInView:self.mapView];   
    CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];

    MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
    annotation.coordinate = touchMapCoordinate;
    self.annotations = [NSMutableArray arrayWithArray:[mapView annotations]];
    for(id a in self.annotations) {
        if(![a isKindOfClass:[MKUserLocation class]]) {
            [mapView removeAnnotation:a];
        }
    }
    [mapView addAnnotation:annotation];
    self.annotations = [NSMutableArray arrayWithArray:[mapView annotations]];
    // NSDictionary *userInfo = [NSDictionary dictionaryWithObject:annotation forKey:@"annotation"];
    // [[NSNotificationCenter defaultCenter] postNotificationName:@"PositionChosen" object:nil userInfo:userInfo];
    [self.mapLocationChoiceDelegate locationChosen:annotation];
    NSLog(@"M: %@", ((ReportScreen *)self.mapLocationChoiceDelegate).textView.text);
}

- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
    if([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
    }
    static NSString *AnnotationIdentifier = @"Annotation";
    MKPinAnnotationView* pinView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
    if (!pinView) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
        pinView.pinColor = MKPinAnnotationColorRed;
        pinView.canShowCallout = YES;
        pinView.animatesDrop = YES;
    } else {
        pinView.annotation = annotation;
    }
    return pinView;
}

@end

Проблема в следующем:

  • ReportScreen подталкивает (фактически выполняет переход к) MapScreen.
  • Если у меня есть какие-то данные в UITextView или если я устанавливаю какое-то состояние для кнопок в ReportScreen и получаю предупреждение о памяти при нажатии MapScreen, как только я возвращаюсь к ReportScreen, все эти поля не отображают эти настройки. По-видимому, textView.text все еще установлен, как и состояния кнопок, они просто не отображаются.

Вопрос: почему?


person Morpheu5    schedule 20.02.2012    source источник
comment
Бывают ли случаи, когда вы не получаете предупреждение о памяти, и оно работает правильно? Я также добавил мапкит в качестве тега к вашему вопросу.   -  person T.J.    schedule 20.02.2012
comment
Да, если я не получаю предупреждений о памяти, все работает отлично. Проблема в том, что MapKit почти всегда заставляет приложение получать предупреждения о памяти. Спасибо за тег :)   -  person Morpheu5    schedule 20.02.2012
comment
Я начинаю подозревать, что это может быть потому, что я делаю все эти вещи в ReportScreen::viewDidLoad и ReportScreen::isReadyToSubmit… просто я не знаю, где еще проделывать все эти трюки. Во всяком случае, вот видео youtube.com/watch?v=F5_8MU83r3M, в котором показано неправильное поведение . Он все еще обрабатывается, но должен скоро стать доступным.   -  person Morpheu5    schedule 21.02.2012
comment
Почти все свойства, которые я создаю с помощью ARC, являются @property (сильными, неатомарными). Почему вы используете @property (неатомарное, сохраняемое)?   -  person T.J.    schedule 21.02.2012
comment
Старые привычки, я думаю. Раньше я делал это еще до появления ARC, а потом погрузился в ARC и раскадровки. надо попробовать их поменять. РЕДАКТИРОВАТЬ Только что попробовал, ничего не изменилось… ДОПОЛНИТЕЛЬНЫЕ РЕДАКТИРОВАНИЯ stackoverflow.com/questions/7796476/ Это говорит о том, что сохранение равно сильному.   -  person Morpheu5    schedule 21.02.2012
comment
Конечно, я забыл упомянуть, что если я прокомментирую [super didReceiveMemoryWarning], я ничего не потеряю, хотя я думаю, что это плохое поведение.   -  person Morpheu5    schedule 21.02.2012