Eu gostaria de armazenar uma série de referências fracas no Swift. A matriz em si não deve ser uma referência fraca - seus elementos devem ser. Eu acho que o Cocoa NSPointerArray
oferece uma versão não tipesafe disso.
179
Eu gostaria de armazenar uma série de referências fracas no Swift. A matriz em si não deve ser uma referência fraca - seus elementos devem ser. Eu acho que o Cocoa NSPointerArray
oferece uma versão não tipesafe disso.
Respostas:
Crie um wrapper genérico como:
Adicione instâncias dessa classe à sua matriz.
Ao definir,
Weak
você pode usarstruct
ouclass
.Além disso, para ajudar a colher o conteúdo da matriz, você pode fazer algo como:
O uso
AnyObject
acima deve ser substituído porT
- mas não acho que a linguagem Swift atual permita uma extensão definida como tal.fonte
Stuff
por um protocolo; veja esta questão relacionadaVocê pode usar o NSHashTable com o fracoObjectsHashTable.
NSHashTable<ObjectType>.weakObjectsHashTable()
Para o Swift 3:
NSHashTable<ObjectType>.weakObjects()
Referência da classe NSHashTable
fonte
Any
mas nãoAnyObject
, como protocolos.MyProtocol: class
eNSHashTable<MyProtocol>.weakObjects()
. "'NSHashTable' requer que 'MyProtocol' seja um tipo de classe.É meio tarde para a festa, mas experimente o meu. Eu implementei como um conjunto, não uma matriz.
WeakObjectSet
Uso
Cuidado que WeakObjectSet não aceita o tipo String, mas NSString. Porque, o tipo String não é um AnyType. Minha versão rápida é
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
.O código pode ser obtido no Gist. https://gist.github.com/codelynx/30d3c42a833321f17d39
** ADICIONADO EM NOV.2017
Atualizei o código para o Swift 4
Como gokeji mencionou, eu descobri que o NSString não será desalocado com base no código em uso. Cocei minha cabeça e escrevi a classe MyString da seguinte maneira.
Em seguida, substitua
NSString
porMyString
assim. Então estranho dizer que funciona.Então, descobri que uma página estranha pode estar relacionada a esse problema.
https://bugs.swift.org/browse/SR-5511
Ele diz que o problema é,
RESOLVED
mas gostaria de saber se isso ainda está relacionado a esse problema. De qualquer forma, as diferenças de comportamento entre MyString ou NSString estão além desse contexto, mas eu apreciaria se alguém descobrisse esse problema.fonte
nil
valores do internoSet
. Então, adicionei umareap()
função mencionada na resposta superior e lembrei-me de ligarreap()
sempre que oWeakObjectSet
acesso for feito.nil
maisNSString
não funciona.UnsafeMutablePointer<T>(&object)
pode mudar aleatoriamente (o mesmo comwithUnsafePointer
). Agora uso uma versão suportada porNSHashTable
: gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d .Esta não é a minha solução. Encontrei-o nos Fóruns de desenvolvedores da Apple .
O @GoZoner tem uma boa resposta, mas trava o compilador Swift.
A seguir, uma versão de um contêiner de objeto fraco não trava o compilador lançado atualmente.
Você pode criar uma matriz desses contêineres:
fonte
EXC_BAD_ACCESS
para mim. Com classe funciona muito bemVocê pode fazer isso criando um objeto wrapper para manter um ponteiro fraco.
E depois usá-los na matriz
fonte
class
para usarweak
vars #protocol Protocol : class { ... }
E o wrapper de estilo funcional?
Basta ligar para o fechamento retornado para verificar se o alvo ainda está vivo.
E você pode armazenar esses fechamentos em uma matriz.
E você pode recuperar os valores fracamente capturados mapeando os fechamentos.
Na verdade, você não precisa de uma função para fazer um fechamento. Basta capturar um objeto diretamente.
fonte
var array: [(x: Int, y: () -> T?)]
. Exatamente o que eu estava procurando.let values = Array(array1.map({ $0() })) part
. Como não é mais uma matriz de fechamentos com referências fracas, os valores serão retidos até que essa matriz seja desalocada. Se eu estiver correto, é importante observar que você nunca deve reter essa matriz,self.items = Array(array1.map({ $0() }))
pois isso supera o objetivo.Eu tive a mesma idéia de criar contêineres fracos com genéricos.
Como resultado, criei o wrapper para
NSHashTable
:Uso:
Não é a melhor solução, porque
WeakSet
pode ser inicializada com qualquer tipo e, se esse tipo não estiver em conformidade comAnyObject
protocolo, o aplicativo falhará por motivos detalhados. Mas não vejo melhor solução no momento.A solução original foi definir
WeakSet
desta maneira:Mas neste caso
WeakSet
não pode ser inicializado com o protocolo:Atualmente, o código acima não pode ser compilado (Swift 2.1, Xcode 7.1).
Foi por isso que deixei de cumprir
AnyObject
e adicionei guardas adicionais comfatalError()
afirmações.fonte
Detalhes
Solução
Opção 1
Uso da opção 1
opção 2
Uso da opção 2
Amostra completa
fonte
protocol TP: class { } class TC { var a = WeakArray<TP>() var b = WeakObjectsArray<TP>() }
protocol TP: class { } class TC<TYPE> where TYPE: TP { var a = WeakObjectsArray<TYPE>() // Use like regular array. With any objects var weakObjectsArray = [TYPE?]() }
delegates
. Então você teria um número de controladores de exibição que gostariam de usar essa funcionalidade. Você esperaria ligarMyManager.delegates.append(self)
. Mas seMyManager
estiver bloqueado para algum tipo genérico, isso não será muito útil.protocol TP: class { } class MyManager { typealias Delegate = AnyObject & TP static var delegates = [Delegate?]() } class A: TP { } class B: TP { } //MyManager.delegates.append(A()) //MyManager.delegates.append(B())
O exemplo existente do WeakContainer é útil, mas realmente não ajuda a usar referências fracas em contêineres rápidos existentes, como Listas e Dicionários.
Se você quiser usar os métodos List, como o contains, o WeakContainer precisará implementar o Equatable. Então, adicionei o código para permitir que o WeakContainer seja equacionável.
No caso de você querer usar o WeakContainer nos dicionários, também o tornei lavável para que possa ser usado como chaves de dicionário.
Também o renomei para WeakObject para enfatizar que isso é apenas para tipos de classe e para diferenciá-lo dos exemplos de WeakContainer:
Isso permite que você faça coisas legais, como usar um dicionário de referências fracas:
fonte
Aqui está como fazer @ grande resposta do GoZoner em conformidade com
Hashable
, por isso pode ser indexado no contentor de objectos como:Set
,Dictionary
,Array
, etc.fonte
Como
NSPointerArray
já lida com a maior parte disso automaticamente, resolvi o problema criando um invólucro com segurança de tipo para ele, o que evita muito do clichê nas outras respostas:Exemplo de uso:
É mais trabalhoso, mas o uso no restante do seu código é IMO muito mais limpo. Se você quiser torná-lo mais parecido com um array, pode até implementar subscrição, torná-lo um
SequenceType
etc., (mas meu projeto só precisaappend
e,forEach
portanto, não tenho o código exato em mãos).fonte
Ainda outra solução para o mesmo problema ... o foco deste é armazenar uma referência fraca a um objeto, mas permitir que você armazene uma estrutura também.
[Não tenho certeza de quão útil é, mas demorou um pouco para acertar a sintaxe]
fonte
Você pode criar um invólucro
Array
. Ou use esta biblioteca https://github.com/NickRybalko/WeakPointerArraylet array = WeakPointerArray<AnyObject>()
É do tipo seguro.fonte
Outras respostas cobriram o ângulo dos genéricos. Pensei em compartilhar um código simples cobrindo o
nil
ângulo.Eu queria uma matriz estática (leia ocasionalmente) de todos os
Label
s existentes no aplicativo, mas não queria vernil
onde estavam os antigos.Nada extravagante, este é o meu código ...
fonte
flatMap
vez defilter
&map
?Baseei isso no trabalho do @Eonil, pois adorei a estratégia de fechamento fraco, mas não queria usar um operador de função para uma variável, pois parecia extremamente contra-intuitivo
O que eu fiz, em vez disso, é o seguinte:
Dessa forma, você pode fazer algo como:
fonte
Esta é a minha solução:
-
fonte
Essa é uma coleção segura do tipo que contém contêineres de objetos fracos. Também remove automaticamente os contêineres / invólucros quando é acessado.
Exemplo:
A coleção personalizada https://gist.github.com/djk12587/46d85017fb3fad6946046925f36cefdc
fonte
Que tal uma abordagem funcional ?
Essa é a idéia principal e, em seguida, adicione qualquer lógica de conveniência para acompanhar o que está na matriz. Por exemplo, pode-se considerar a mesma abordagem com um Dicionário usando key como uma maneira de encontrar o que está lá.
fonte