UIPopovercontroller dealloc alcançado enquanto o popover ainda está visível

111

Garanto que procurei uma resposta no SO para minha pergunta, mas nenhuma delas foi útil. Aqui eu tenho um código simples que deve apresentar um UIImagePickerControllerdentro de 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];
}

Agora, mesmo da primeira vez, sou [UIPopoveController dealloc]contatado enquanto ... erro e o programa trava. Não estou fazendo nenhuma retenção, liberação ou liberação automática de acordo com o ARC. Há alguma consideração especial UIPopoverControllersao se beneficiar do ARC?

Mikayil Abdullayev
fonte

Respostas:

203

UIPopoverControllers deve sempre ser mantido em uma variável de instância. É uma boa prática criar uma propriedade forte para ele.

ATUALIZAR:

A partir do iOS 8, você deve estar usando UIPopoverPresentationController. Então você não precisa manter uma referência ao popover porque ele é gerenciado pelo controlador de apresentação.

Exemplo de código (funciona tanto no iPhone quanto no 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];
Felix
fonte
1
Ah eu vejo. Mas isso não é como um UIAlertView? Eu nunca tive um ivar para ele, eu apenas aloco o init onde eu preciso, mostro e então [costumava] liberar. Em que o popovercontroller é diferente?
Mikayil Abdullayev
17
@Mikayil O alertView é retido por sua superview (como todas as views), mas o popoverController não é uma view, então não tem uma superview, então não será retido por ninguém se você não a reter (ou armazene-o em uma variável forte que tenha um escopo maior do que o método atual - por exemplo, um iVar).
fzwo
1
Mas ainda estou confuso sobre a retenção da contagem do UIPopoverController. Porque eu coloquei uma verificação antes de alocar e inicializar um. E só se for nulo, aloco um novo. Mas depois de alocá-lo pela primeira vez, nunca recebo nada. Quer dizer, chamo um método uma vez. Lá eu aloco e inicializo meu ivar. E da próxima vez, quando chamo esse método novamente, encontro meu ivar já alocado. Se o ARC cuidar disso, quando ele o liberará. Ou ele é liberado automaticamente?
Mikayil Abdullayev
@Mikayil ivars são liberados pela ARC quando o objeto é desalocado ou quando você os define como nulo
Felix
mas eles não mencionaram isso na documentação, na seção Como usar eles usam a variável local
Amit Battan
11

Quando a função é encerrada, não há nenhuma outra referência ao controlador popover, então ele é desalocado muito cedo.

Em vez disso, tente adicioná-lo como um membro de sua classe.

Tim

Tarmes
fonte
Eu ainda não deveria ser capaz de vê-lo antes de ele ser desalocado?
Mikayil Abdullayev
10

Adicionando o que @ phix23 respondeu, crie a propriedade * poc assim:

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

e então mudar

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

para

self.poc = [[UIPopoverController alloc] 
                            initWithContentViewController:picker];
Orafaelreis
fonte
11
Você não precisa colocá-lo em seu arquivo .h. Isso o tornaria público e, a menos que você queira, apenas torne-o uma propriedade em seu arquivo .m.
Joshua Dance