Eu tenho uma matriz que é composta AnyObject
. Eu quero iterar sobre ele e encontrar todos os elementos que são instâncias de matriz.
Como posso verificar se um objeto é de um determinado tipo no Swift?
Eu tenho uma matriz que é composta AnyObject
. Eu quero iterar sobre ele e encontrar todos os elementos que são instâncias de matriz.
Como posso verificar se um objeto é de um determinado tipo no Swift?
Respostas:
Se você deseja verificar um tipo específico, pode fazer o seguinte:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
Você pode usar "como!" e isso gerará um erro de tempo de execução se obj
não for do tipo[String]
let stringArray = obj as! [String]
Você também pode verificar um elemento de cada vez:
let items : [Any] = ["Hello", "World"]
for obj in items {
if let str = obj as? String {
// obj is a String. Do something with str
}
else {
// obj is not a String
}
}
?
não está presente? Soa como as
e ?
quando combinado irá realizar verificação de tempo de execução. Quando seria apropriado usar as
sem ?
? Desde já, obrigado.
as
sem o ?
se não houver como o seu programa se recuperar do objeto que não é desse tipo, porque o programa será interrompido imediatamente se não for. O uso de ?
na if
instrução permite que o programa continue.
?
nesse caso executaria uma verificação de tipo "genérico", se sim, na cláusula if, se não, na cláusula else. Sem o ?
else nunca seria inserido e, como você apontou, causa um erro de tempo de execução. Obrigado novamente.
?
permite que a atribuição retorne, nil
fazendo com que a instrução if retorne false
e, portanto, caia na instrução else. No entanto, penso que a explicação ajuda com a compreensão, mas if let
é na verdade um caso especial no compilador
No Swift 2.2 - 5, agora você pode:
if object is String
{
}
Em seguida, para filtrar sua matriz:
let filteredArray = originalArray.filter({ $0 is Array })
Se você tiver vários tipos para verificar:
switch object
{
case is String:
...
case is OtherClass:
...
default:
...
}
object
como um String
suporte interno (pelo menos no Swift 2), enquanto que com a let
solução, você pode fazê-lo.
object
o bloco.
object.uppercaseString
porque o tipo da variável não é convertido para esse tipo, você apenas verificou se o objeto (apontado pela variável) é umString
Se você deseja apenas saber se um objeto é um subtipo de um determinado tipo, existe uma abordagem mais simples:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
func area (shape: Shape) -> Double {
if shape is Circle { ... }
else if shape is Rectangle { ... }
}
“Use o operador de verificação de tipo (is) para verificar se uma instância é de um determinado tipo de subclasse. O operador de verificação de tipo retorna true se a instância for desse tipo de subclasse e false se não for. ” Trecho de: Apple Inc. “A linguagem de programação Swift”. iBooks .
No texto acima, a frase 'de um determinado tipo de subclasse' é importante. O uso de is Circle
e is Rectangle
é aceito pelo compilador porque esse valor shape
é declarado como Shape
(uma superclasse de Circle
e Rectangle
).
Se você estiver usando tipos primitivos, a superclasse seria Any
. Aqui está um exemplo:
21> func test (obj:Any) -> String {
22. if obj is Int { return "Int" }
23. else if obj is String { return "String" }
24. else { return "Any" }
25. }
...
30> test (1)
$R16: String = "Int"
31> test ("abc")
$R17: String = "String"
32> test (nil)
$R18: String = "Any"
is
ainda funcionaria aqui? Obrigado.
object
as Any
. Atualizado com um exemplo.
AnyObject
é sugerida, parece ter sido replicada por AnyObject
não herdar NSObject
. Se Any
for diferente, isso também seria uma ótima solução. Obrigado.
Eu tenho 2 maneiras de fazer isso:
if let thisShape = aShape as? Square
Ou:
aShape.isKindOfClass(Square)
Aqui está um exemplo detalhado:
class Shape { }
class Square: Shape { }
class Circle: Shape { }
var aShape = Shape()
aShape = Square()
if let thisShape = aShape as? Square {
println("Its a square")
} else {
println("Its not a square")
}
if aShape.isKindOfClass(Square) {
println("Its a square")
} else {
println("Its not a square")
}
Editar: 3 agora:
let myShape = Shape()
if myShape is Shape {
print("yes it is")
}
isKindOfClass
é um método do NSObject
protocolo; ele só deve trabalhar para as classes que adotam (todas as classes descendentes de NSObject, além de todo o costume classe Swift, que adota-lo explicitamente)
para swift4:
if obj is MyClass{
// then object type is MyClass Type
}
Suponha que drawTriangle é uma instância do UIView. Para verificar se drawTriangle é do tipo UITableView:
No Swift 3 ,
if drawTriangle is UITableView{
// in deed drawTriangle is UIView
// do something here...
} else{
// do something here...
}
Isso também pode ser usado para classes definidas por você. Você pode usar isso para verificar as subvisões de uma visualização.
Por que não usar a funcionalidade incorporada criada especialmente para esta tarefa?
let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)
Result: "Array<Any>"
Esteja avisado sobre isso:
var string = "Hello" as NSString
var obj1:AnyObject = string
var obj2:NSObject = string
print(obj1 is NSString)
print(obj2 is NSString)
print(obj1 is String)
print(obj2 is String)
Todas as quatro últimas linhas retornam verdadeiras, porque se você digitar
var r1:CGRect = CGRect()
print(r1 is String)
... ele imprime "false", é claro, mas um aviso diz que a conversão de CGRect para String falha. Portanto, algum tipo é ponte, e a palavra-chave 'is' chama uma conversão implícita.
Você deve usar melhor um destes:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
Se você quiser apenas verificar a classe sem receber um aviso por causa do valor definido não utilizado (deixe someVariable ...), basta substituir o material let por um booleano:
if (yourObject as? ClassToCompareWith) != nil {
// do what you have to do
}
else {
// do something else
}
O Xcode propôs isso quando eu usei o let e não usei o valor definido.
Por que não usar algo assim
fileprivate enum types {
case typeString
case typeInt
case typeDouble
case typeUnknown
}
fileprivate func typeOfAny(variable: Any) -> types {
if variable is String {return types.typeString}
if variable is Int {return types.typeInt}
if variable is Double {return types.typeDouble}
return types.typeUnknown
}
no Swift 3.
Swift 4.2. No meu caso, usando a função isKind.
isKind (of :) Retorna um valor booleano que indica se o receptor é uma instância de uma determinada classe ou uma instância de qualquer classe que herda dessa classe.
let items : [AnyObject] = ["A", "B" , ... ]
for obj in items {
if(obj.isKind(of: NSString.self)){
print("String")
}
}
Leia mais https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind
Apenas para completar, com base na resposta aceita e em algumas outras:
let items : [Any] = ["Hello", "World", 1]
for obj in items where obj is String {
// obj is a String. Do something with str
}
Mas você também pode ( compactMap
também "mapeia" os valores que filter
não o fazem):
items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }
E uma versão usando switch
:
for obj in items {
switch (obj) {
case is Int:
// it's an integer
case let stringObj as String:
// you can do something with stringObj which is a String
default:
print("\(type(of: obj))") // get the type
}
}
Mas, mantendo a questão, para verificar se é uma matriz (ou seja [String]
):
let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]
for obj in items {
if let stringArray = obj as? [String] {
print("\(stringArray)")
}
}
Ou de maneira mais geral (veja esta outra resposta da pergunta ):
for obj in items {
if obj is [Any] {
print("is [Any]")
}
if obj is [AnyObject] {
print("is [AnyObject]")
}
if obj is NSArray {
print("is NSArray")
}
}
as?
nem sempre fornecerá o resultado esperado porque as
não testa se um tipo de dados é de um tipo específico, mas apenas se um tipo de dados pode ser convertido ou representado como um tipo específico.
Considere este código por exemplo:
func handleError ( error: Error ) {
if let nsError = error as? NSError {
Todos os tipos de dados em conformidade com o Error
protocolo podem ser convertidos em um NSError
objeto, portanto, sempre será bem-sucedido . No entanto, isso não significa que error
seja de fato umNSError
objeto ou uma subclasse dele.
Uma verificação de tipo correta seria:
func handleError ( error: Error ) {
if type(of: error) == NSError.self {
No entanto, isso verifica apenas o tipo exato. Se você deseja incluir também a subclasse de NSError
, você deve usar:
func handleError ( error: Error ) {
if error is NSError.Type {
Se você tiver uma resposta como esta:
{
"registeration_method": "email",
"is_stucked": true,
"individual": {
"id": 24099,
"first_name": "ahmad",
"last_name": "zozoz",
"email": null,
"mobile_number": null,
"confirmed": false,
"avatar": "http://abc-abc-xyz.amazonaws.com/images/placeholder-profile.png",
"doctor_request_status": 0
},
"max_number_of_confirmation_trials": 4,
"max_number_of_invalid_confirmation_trials": 12
}
e você deseja verificar o valor is_stucked
que será lido como AnyObject, tudo que você precisa fazer é isso
if let isStucked = response["is_stucked"] as? Bool{
if isStucked{
print("is Stucked")
}
else{
print("Not Stucked")
}
}
Se você não souber que receberá uma matriz de dicionários ou dicionário único na resposta do servidor, precisará verificar se o resultado contém uma matriz ou não.
No meu caso, sempre recebendo uma matriz de dicionários, exceto uma vez. Então, para lidar com isso, usei o código abaixo para o swift 3.
if let str = strDict["item"] as? Array<Any>
Aqui como? Matriz verifica se o valor obtido é matriz (de itens do dicionário). Caso contrário, você pode manipular se for um item de dicionário único que não é mantido dentro de uma matriz.
Swift 5.2 e versão Xcode: 11.3.1 (11C504)
Aqui está minha solução de verificar o tipo de dados:
if let typeCheck = myResult as? [String : Any] {
print("It's Dictionary.")
} else {
print("It's not Dictionary.")
}
Espero que ajude você.