У мене є масив, який складається AnyObject
. Я хочу перебрати його і знайти всі елементи, які є екземплярами масиву.
Як я можу перевірити, чи є об'єкт даного типу в Swift?
У мене є масив, який складається AnyObject
. Я хочу перебрати його і знайти всі елементи, які є екземплярами масиву.
Як я можу перевірити, чи є об'єкт даного типу в Swift?
Відповіді:
Якщо ви хочете перевірити певний тип, ви можете зробити наступне:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
Ви можете використовувати "як!" і це призведе до помилки виконання, якщо obj
вона не має типу[String]
let stringArray = obj as! [String]
Ви також можете перевірити один елемент одночасно:
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
}
}
?
немає. Це здається, as
і в ?
поєднанні виконуватимуть перевірку виконання. Коли було б доцільно використовувати as
без ?
? Заздалегідь спасибі.
as
без того, ?
якщо немає можливості, щоб ваша програма могла відновитись із об'єкта, який не має такого типу, оскільки програма негайно зупиниться, якщо її немає. Використання ?
в if
операторі дозволяє програмі продовжувати роботу.
?
цього випадку виконає перевірку типу "загального", якщо так, до пункту "if", якщо ні - до "іншого". Без ?
іншого ніколи не буде введено, і, як ви вказали, викликати помилку виконання. Знову дякую.
?
Дозволяє присвоювання повернутися nil
викликаючи якщо заяву повернення false
і , отже , провалюючись в іншу заяву. Однак я думаю, що пояснення допомагає з розумінням, але if let
насправді це особливий випадок у компіляторі
У Swift 2.2 - 5 ви можете:
if object is String
{
}
Потім відфільтруйте масив:
let filteredArray = originalArray.filter({ $0 is Array })
Якщо у вас є кілька типів для перевірки:
switch object
{
case is String:
...
case is OtherClass:
...
default:
...
}
object
як String
внутрішню дужку (принаймні у Swift 2), тоді як з let
рішенням ви можете це зробити.
object
в блоці добре.
object.uppercaseString
тому що тип змінної не приводиться до цього типу, ви просто перевірили, що об'єкт (вказаний змінною)String
Якщо ви хочете лише знати, чи об’єкт є підтипом даного типу, тоді існує більш простий підхід:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
func area (shape: Shape) -> Double {
if shape is Circle { ... }
else if shape is Rectangle { ... }
}
“Використовуйте оператор перевірки типу (є), щоб перевірити, чи є примірник певного типу підкласу. Оператор перевірки типу повертає true, якщо екземпляр цього типу підкласу, а false, якщо його немає. " Уривок: Apple Inc. "Мова швидкого програмування". iBooks .
У зазначеному вище словосполучення "певного типу підкласу" є важливим. Використання is Circle
і is Rectangle
приймається компілятором, оскільки це значення shape
оголошується як Shape
(суперклас Circle
і Rectangle
).
Якщо ви використовуєте примітивні типи, суперклас був би Any
. Ось приклад:
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
усе ще працюватиме тут? Дякую.
object
як Any
. Оновлено прикладом.
AnyObject
пропонується, схоже, було відмовлено у зв'язку з тим, що AnyObject
не успадковувались від NSObject
. Якщо Any
інакше, то це було б насправді і чудовим рішенням. Дякую.
У мене є два способи це зробити:
if let thisShape = aShape as? Square
Або:
aShape.isKindOfClass(Square)
Ось детальний приклад:
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")
}
Редагувати: 3 зараз:
let myShape = Shape()
if myShape is Shape {
print("yes it is")
}
isKindOfClass
- метод NSObject
протоколу; він повинен працювати лише для класів, які приймають його (усі класи, що походять від NSObject, плюс будь-який спеціальний клас Swift, який явно приймає його)
для swift4:
if obj is MyClass{
// then object type is MyClass Type
}
Припустимо drawTriangle - це примірник UIView. Щоб перевірити, чи drawTriangle має тип UITableView:
У Swift 3 ,
if drawTriangle is UITableView{
// in deed drawTriangle is UIView
// do something here...
} else{
// do something here...
}
Це також може бути використане для занять, визначених вами. Ви можете скористатися цією функцією, щоб перевірити підгляди подання.
Чому б не використати вбудований функціонал, побудований спеціально для цього завдання?
let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)
Result: "Array<Any>"
Попереджуйте про це:
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)
Усі чотири останні рядки повертаються як істинні, це тому, що якщо ви вводите текст
var r1:CGRect = CGRect()
print(r1 is String)
... він, звичайно, друкує "помилково", але попередження говорить про те, що передача від CGRect до String не вдається. Таким чином, якийсь тип з'єднаний, а ключове слово "є" викликає неявний склад.
Вам краще скористатися одним із таких:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
Якщо ви просто хочете перевірити клас, не отримуючи попередження через невикористане визначене значення (нехай деякіVariable ...), ви можете просто замінити пусті речі булевими:
if (yourObject as? ClassToCompareWith) != nil {
// do what you have to do
}
else {
// do something else
}
Xcode запропонував це, коли я використовував пусковий шлях і не використовував визначене значення.
Чому б не використати щось подібне
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
}
у Swift 3.
Swift 4.2, У моєму випадку за допомогою функції isKind.
isKind (of :) Повертає булеве значення, яке вказує, чи є одержувач екземпляром даного класу чи екземпляром будь-якого класу, який успадковує цей клас.
let items : [AnyObject] = ["A", "B" , ... ]
for obj in items {
if(obj.isKind(of: NSString.self)){
print("String")
}
}
Детальніше https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind
Просто задля повноти на основі прийнятої відповіді та деяких інших:
let items : [Any] = ["Hello", "World", 1]
for obj in items where obj is String {
// obj is a String. Do something with str
}
Але ви також можете ( compactMap
також "відображати" значення, які filter
не відповідають):
items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }
І версія, що використовує 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
}
}
Але дотримуючись питання, щоб перевірити, чи це масив (тобто [String]
):
let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]
for obj in items {
if let stringArray = obj as? [String] {
print("\(stringArray)")
}
}
Або загалом (див. Цю відповідь на інше питання ):
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?
не завжди дасть вам очікуваний результат , тому що as
не перевіряє , є чи тип даних є певного роду , але тільки якщо тип даних може бути перетворений в або представити в вигляді певного виду.
Розглянемо, наприклад, цей код:
func handleError ( error: Error ) {
if let nsError = error as? NSError {
Кожен тип даних, що відповідає Error
протоколу, може бути перетворений на NSError
об'єкт, тому це завжди буде успішним . Але це не означає, що error
насправді є NSError
об'єктом або його підкласом.
Правильна перевірка типу:
func handleError ( error: Error ) {
if type(of: error) == NSError.self {
Однак це перевіряє лише точний тип. Якщо ви також хочете включити підклас NSError
, слід використовувати:
func handleError ( error: Error ) {
if error is NSError.Type {
Якщо у вас є така відповідь:
{
"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
}
і ви хочете перевірити значення, is_stucked
яке буде читатися як AnyObject, все, що вам потрібно зробити, це це
if let isStucked = response["is_stucked"] as? Bool{
if isStucked{
print("is Stucked")
}
else{
print("Not Stucked")
}
}
Якщо ви не знаєте, що у відповіді від сервера ви отримаєте масив словників чи єдиний словник, вам потрібно перевірити, чи містить результат масив чи ні.
У моєму випадку завжди отримується масив словників, крім одного разу. Отже, для обробки я використовував наведений нижче код для швидкого 3.
if let str = strDict["item"] as? Array<Any>
Тут як? Масив перевіряє, чи є отримане значення масивом (елементів словника). В іншому випадку ви можете обробити, якщо це єдиний елемент словника, який не зберігається всередині масиву.
Версія Swift 5.2 та Xcode: 11.3.1 (11C504)
Ось моє рішення щодо перевірки типу даних:
if let typeCheck = myResult as? [String : Any] {
print("It's Dictionary.")
} else {
print("It's not Dictionary.")
}
Сподіваюся, це допоможе тобі.