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
ก่อให้เกิดคำสั่ง if เพื่อส่งคืนfalse
และทำให้เกิดการผ่านไปยังคำสั่ง else แต่ผมคิดว่าคำอธิบายที่จะช่วยให้มีความเข้าใจ แต่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
ภายในวงเล็บ (อย่างน้อยในสวิฟท์ 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 { ... }
}
“ ใช้ตัวดำเนินการตรวจสอบชนิด (คือ) เพื่อตรวจสอบว่าอินสแตนซ์นั้นเป็นประเภทย่อยบางประเภทหรือไม่ ตัวดำเนินการตรวจสอบชนิดจะคืนค่าเป็นจริงถ้าอินสแตนซ์นั้นเป็นประเภทย่อยและเป็นเท็จถ้าไม่ใช่” ข้อความที่ตัดตอนมาจาก: Apple Inc. “ ภาษาการเขียนโปรแกรม Swift” iBooks
ในข้างต้นวลี 'ของประเภทรองบางอย่าง' เป็นสิ่งสำคัญ การใช้is Circle
และis Rectangle
เป็นที่ยอมรับโดยคอมไพเลอร์เพราะค่าshape
ดังกล่าวถูกประกาศเป็นShape
(ซูเปอร์คลาสของCircle
และRectangle
)
หากคุณกำลังใช้ประเภทดั้งเดิม superclass 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
แตกต่างกันนี่ก็เป็นทางออกที่ดีเช่นกัน ขอบคุณ
ฉันมี 2 วิธีในการทำ:
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 หรือไม่:
ในสวิฟท์ 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)
... มันพิมพ์ "false" แน่นอน แต่คำเตือนบอกว่า Cast จาก CGRect to String ล้มเหลว ดังนั้นบางประเภทจะเชื่อมโยงกันและคำหลัก 'คือ' จึงเรียกการส่งโดยนัย
คุณควรใช้หนึ่งในสิ่งต่อไปนี้:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
หากคุณต้องการตรวจสอบคลาสโดยไม่ได้รับคำเตือนเนื่องจากค่าที่ไม่ได้ใช้ (ให้ someVariable ... ) คุณสามารถแทนที่สิ่งที่อนุญาตด้วยบูลีน:
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
myObject as? String
ผลตอบแทนที่ได้nil
ถ้าไม่ได้เป็นmyObject
String
มิฉะนั้นจะส่งคืน a String?
เพื่อให้คุณสามารถเข้าถึงสตริงได้ด้วยตนเองmyObject!
หรือส่งมันmyObject! as String
อย่างปลอดภัย
สวิฟท์ 3:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
if aShape.isKind(of: Circle.self) {
}
เพียงเพื่อความสมบูรณ์ตามคำตอบที่ยอมรับและอื่น ๆ :
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")
}
}
หากคุณไม่ทราบว่าคุณจะได้รับชุดพจนานุกรมหรือพจนานุกรมเดี่ยวในการตอบสนองจากเซิร์ฟเวอร์คุณต้องตรวจสอบว่าผลลัพธ์มีอาร์เรย์หรือไม่
ในกรณีของฉันมักจะได้รับพจนานุกรมหลายครั้งยกเว้นครั้งเดียว ดังนั้นเพื่อจัดการว่าฉันใช้รหัสด้านล่างสำหรับ swift 3
if let str = strDict["item"] as? Array<Any>
ที่นี่เป็นอย่างไร Array ตรวจสอบว่าค่าที่ได้รับเป็นอาร์เรย์ (ของรายการพจนานุกรม) ในกรณีอื่นคุณสามารถจัดการได้หากเป็นรายการพจนานุกรมเดี่ยวซึ่งไม่ได้เก็บไว้ในอาร์เรย์
รุ่น 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.")
}
ฉันหวังว่ามันจะช่วยคุณ