Le dealloc d'UIPopovercontroller est atteint alors que le popover est toujours visible

111

Je vous assure que j'ai cherché une réponse dans SO pour ma question, mais aucune n'a été utile. Ici, j'ai un code simple qui devrait présenter un UIImagePickerControllerdans un UIPopoverController:

-(void)takePicture:(id)sender{
UIImagePickerController *picker=[[UIImagePickerController alloc] init];
picker.delegate=self;
picker.sourceType=UIImagePickerControllerSourceTypeCamera;
picker.allowsEditing=YES;
UIPopoverController *poc=[[UIPopoverController alloc] 
                            initWithContentViewController:picker];
[poc presentPopoverFromBarButtonItem:bbItem 
            permittedArrowDirections:UIPopoverArrowDirectionAny
                            animated:NO];
}

Maintenant, même dès la première fois que je suis [UIPopoveController dealloc]atteint alors que ... une erreur et le programme se bloque. Je ne fais aucune rétention, relase ou autoreleases selon l'ARC. Y a-t-il une considération particulière UIPopoverControllerslorsque vous bénéficiez de l'ARC?

Mikayil Abdullayev
la source

Réponses:

203

UIPopoverControllers doit toujours être contenu dans une variable d'instance. C'est une bonne pratique de créer une propriété solide pour cela.

METTRE À JOUR:

À partir d'iOS 8, vous devriez utiliser UIPopoverPresentationController. Ensuite, vous n'avez pas besoin de conserver une référence au popover car il est géré par le contrôleur de présentation.

Exemple de code (fonctionne à la fois sur iPhone et iPad):

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.allowsEditing = YES;
picker.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController* popoverPC = picker.popoverPresentationController;
popoverPC.barButtonItem = bbItem;
popoverPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:picker animated:YES completion:nil];
Félix
la source
1
Oh je vois. Mais n'est-ce pas comme un UIAlertView? Je n'ai jamais d'ivar pour cela, je l'alloue juste là où j'en ai besoin, je le montre et ensuite je le libère. En quoi le popovercontroller est-il différent?
Mikayil Abdullayev
17
@Mikayil L'alerteView est conservée par son superview (comme toutes les vues), mais le popoverController n'est pas une vue, donc n'a pas de superview, donc ne sera retenu par personne si vous ne le retenez pas (ou stockez-le dans une variable forte dont la portée est plus longue que la méthode actuelle - par exemple une iVar).
fzwo le
1
Mais je suis toujours confus au sujet du nombre de rétention du UIPopoverController. Parce que j'ai mis un chèque avant d'en allouer et d'en lancer un. Et seulement si c'est nul, j'en attribue un nouveau. Mais après l'avoir alloué pour la première fois, je ne l'obtiens jamais. Je veux dire, j'appelle une méthode une fois. Là, j'attribue et initie mon ivar. Et la prochaine fois que j'appelle à nouveau cette méthode cette fois, je trouve mon ivar déjà alloué. Si ARC s'occupe de cela, alors quand le libère-t-il. Ou est-ce qu'il le libère automatiquement?
Mikayil Abdullayev
@Mikayil ivars sont libérés par ARC lorsque l'objet est désalloué ou lorsque vous les définissez sur nil
Felix
mais ils ne l'ont pas mentionné dans la documentation, dans la section Comment utiliser , ils utilisent une variable locale
Amit Battan
11

Lorsque la fonction se termine, il n'y a aucune autre référence au contrôleur de popover, il est donc désalloué trop tôt.

Essayez plutôt de l'ajouter en tant que membre de votre classe.

Tim

tarmes
la source
Ne devrais-je pas toujours pouvoir le voir avant qu'il ne soit désalloué?
Mikayil Abdullayev
10

En ajoutant ce que @ phix23 a répondu, créez la propriété * poc comme ceci:

@property (nonatomic, retain) IBOutlet UIPopoverController *poc;

puis changez

UIPopoverController *poc = [[UIPopoverController alloc] 
                            initWithContentViewController:picker];

pour

self.poc = [[UIPopoverController alloc] 
                            initWithContentViewController:picker];
orafaelreis
la source
11
Vous n'êtes pas obligé de le mettre dans votre fichier .h. Cela le rendrait public et à moins que vous ne le souhaitiez, faites-en simplement une propriété dans votre fichier .m.
Joshua Dance