O NSObject
método performSelector:withObject:afterDelay:
me permite invocar um método no objeto com um argumento de objeto após um certo tempo. Ele não pode ser usado para métodos com um argumento não objeto (por exemplo, ints, floats, structs, ponteiros não objeto, etc.).
Qual é a maneira mais simples de obter a mesma coisa com um método com um argumento não objeto? Sei que para regular performSelector:withObject:
, a solução é usar NSInvocation
(o que por sinal é bem complicado). Mas não sei como lidar com a parte do "atraso".
Obrigado,
objective-c
cocoa
user102008
fonte
fonte
Respostas:
Aqui está o que eu costumava chamar de algo que não conseguia mudar usando NSInvocation:
fonte
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? Ou você quer dizer que ainvoke
mensagem está no método que você executa após o atraso?Apenas envolva o float, boolean, int ou similar em um NSNumber.
Para structs, não conheço uma solução prática, mas você poderia fazer uma classe ObjC separada que possui tal struct.
fonte
nil
por umBOOL
parâmetro para receberNO
(FALSE
)NÃO USE ESTA RESPOSTA. EU SÓ DEIXOU PARA FINS HISTÓRICOS. VEJA OS COMENTÁRIOS ABAIXO.
Existe um truque simples se for um parâmetro BOOL.
Passe nulo para NÃO e auto para SIM. nil é convertido para o valor BOOL de NO. self é convertido para o valor BOOL de YES.
Esta abordagem falha se for qualquer coisa diferente de um parâmetro BOOL.
Assumir a si mesmo é um UIView.
fonte
if ()
teste nele, mas é concebível que algum código dependerá de ele ser 0 ou 1, e assim ganhou não trate algum valor de endereço grande como sendo igual a 1 (SIM).self
com endereço como0x0123400
. Com essa abordagem, você receberá NÃO em vez de SIM em 0,4% dos casos. Pior, com essa probabilidade, essa solução pode passar em todos os testes e revelar depois.Talvez NSValue , apenas certifique-se de que seus ponteiros ainda sejam válidos após o atraso (ou seja, nenhum objeto alocado na pilha).
fonte
NSValue
(se possível) para o esperadotype
?Eu sei que esta é uma pergunta antiga, mas se você estiver criando iOS SDK 4+, você pode usar blocos para fazer isso com muito pouco esforço e torná-lo mais legível:
fonte
PerformSelector: WithObject sempre pega um objeto, então para passar argumentos como int / double / float etc ..... Você pode usar algo assim.
Da mesma forma, você pode usar [NSNumber numberWithInt:] etc .... e no método de recebimento, você pode converter o número em seu formato como [número int] ou [número duplo].
fonte
Os blocos são o caminho a percorrer. Você pode ter parâmetros complexos, segurança de tipo, e é muito mais simples e seguro do que a maioria das respostas antigas aqui. Por exemplo, você pode simplesmente escrever:
Os blocos permitem que você capture listas de parâmetros arbitrários, objetos de referência e variáveis.
Implementação de apoio (básico):
Exemplo:
Veja também a resposta de Michael (+1) para outro exemplo.
fonte
Eu sempre recomendo que você use NSMutableArray como o objeto a ser transmitido. Isso porque você pode passar vários objetos, como o botão pressionado e outros valores. NSNumber, NSInteger e NSString são apenas contêineres de algum valor. Certifique-se de que, ao obter o objeto da matriz, você se refere a um tipo de recipiente correto. Você precisa passar os contêineres NS. Lá você pode testar o valor. Lembre-se de que os contêineres usam isEqual quando os valores são comparados.
fonte
Eu também queria fazer isso, mas com um método que recebe um parâmetro BOOL. Envolvendo o valor bool com NSNumber, FALHA AO PASSAR O VALOR. Eu não tenho ideia do porquê.
Então acabei fazendo um hack simples. Eu coloco o parâmetro necessário em outra função fictícia e chamo essa função usando o performSelector, onde withObject = nil;
fonte
-performSelector[...]
método espera um objeto (em vez de um tipo de dados primitivo) e não sabe que o seletor chamado aceita um booleano, talvez o endereço (valor do ponteiro) daNSNumber
instância seja cegamente 'convertido' emBOOL
(= diferente de zero, ou sejaTRUE
). Talvez o tempo de execução pudesse ser mais inteligente do que isso e reconhecer um booleano zero envolvido em umNSNumber
!Acho que a maneira mais rápida (mas um tanto suja) de fazer isso é invocando objc_msgSend diretamente. No entanto, é perigoso invocá-lo diretamente porque você precisa ler a documentação e certificar-se de que está usando a variante correta para o tipo de valor de retorno e porque objc_msgSend é definido como vararg para conveniência do compilador, mas na verdade é implementado como cola de montagem rápida . Aqui está um código usado para chamar um método delegado - [delegate integerDidChange:] que leva um único argumento inteiro.
Isso primeiro salva o seletor, pois vamos nos referir a ele várias vezes e seria fácil criar um erro de digitação. Em seguida, verifica se o delegado realmente responde ao seletor - pode ser um protocolo opcional. Em seguida, ele cria um tipo de ponteiro de função que especifica a assinatura real do seletor. Lembre-se de que todas as mensagens Objective-C têm dois primeiros argumentos ocultos, o objeto que está sendo enviado e o seletor que está sendo enviado. Em seguida, criamos um ponteiro de função do tipo apropriado e o configuramos para apontar para a função objc_msgSend subjacente. Lembre-se de que, se o valor de retorno for um float ou struct, você precisará usar uma variante diferente de objc_msgSend. Finalmente, envie a mensagem usando o mesmo mecanismo que Objective-C usa sob as folhas.
fonte
Você poderia apenas usar NSTimer para chamar um seletor:
fonte
yourMethod:
em seu exemplo é o próprio cronômetro, e você não passou por nadauserInfo
. Mesmo se você usasseuserInfo
, ainda teria que encaixotar o valor, como prejudica e Remus Rusanu sugeriu.Chamar performSelector com um NSNumber ou outro NSValue não funcionará. Em vez de usar o valor de NSValue / NSNumber, ele efetivamente lançará o ponteiro para um int, float ou qualquer outra coisa e usará isso.
Mas a solução é simples e óbvia. Crie o NSInvocation e chame
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
fonte
Talvez ... ok, muito provavelmente, estou faltando alguma coisa, mas por que não apenas criar um tipo de objeto, digamos NSNumber, como um contêiner para sua variável de tipo não-objeto, como CGFloat?
fonte