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 objnã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 ase ?quando combinado irá realizar verificação de tempo de execução. Quando seria apropriado usar assem ?? Desde já, obrigado.
assem 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 ifinstruçã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, nilfazendo com que a instrução if retorne falsee, 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:
...
}
objectcomo um Stringsuporte interno (pelo menos no Swift 2), enquanto que com a letsolução, você pode fazê-lo.
objecto bloco.
object.uppercaseStringporque 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 Circlee is Rectangleé aceito pelo compilador porque esse valor shapeé declarado como Shape(uma superclasse de Circlee 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"
isainda funcionaria aqui? Obrigado.
objectas Any. Atualizado com um exemplo.
AnyObjecté sugerida, parece ter sido replicada por AnyObjectnão herdar NSObject. Se Anyfor 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 NSObjectprotocolo; 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 ( compactMaptambém "mapeia" os valores que filternã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 asnã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 Errorprotocolo podem ser convertidos em um NSErrorobjeto, portanto, sempre será bem-sucedido . No entanto, isso não significa que errorseja 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_stuckedque 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ê.