ฉันจะพิมพ์ประเภทหรือคลาสของตัวแปรใน Swift ได้อย่างไร


335

มีวิธีพิมพ์ชนิดรันไทม์ของตัวแปรอย่างรวดเร็วหรือไม่? ตัวอย่างเช่น:

var now = NSDate()
var soon = now.dateByAddingTimeInterval(5.0)

println("\(now.dynamicType)") 
// Prints "(Metatype)"

println("\(now.dynamicType.description()")
// Prints "__NSDate" since objective-c Class objects have a "description" selector

println("\(soon.dynamicType.description()")
// Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method

ในตัวอย่างข้างต้นที่ผมกำลังมองหาวิธีที่จะแสดงให้เห็นว่าตัวแปร "เร็ว ๆ นี้" เป็นประเภทหรืออย่างน้อยImplicitlyUnwrappedOptional<NSDate>NSDate!


43
@JasonMArcher บอกฉันว่าสิ่งนี้ซ้ำกันได้อย่างไรหากคำถามที่คุณเชื่อมโยงถูกถาม 4 วันหลังจากนี้
akashivskyy

มีคำถามจำนวนหนึ่งเกี่ยวกับการทดสอบประเภทของวัตถุ Swift หรืออ่านประเภทของวัตถุ Swift เราเพียงแค่ค้นหาคำถามที่ดีที่สุดเพื่อใช้เป็นคำถาม "หลัก" สำหรับเรื่องนี้ สำเนาที่แนะนำมีคำตอบที่ละเอียดกว่า นี่ไม่ได้เป็นการบอกว่าคุณทำอะไรผิดพลาดเพียงแค่เราพยายามลดความยุ่งเหยิง
JasonMArcher

4
สำเนาที่แนะนำไม่ได้ตอบคำถามเดียวกัน Type.self ไม่สามารถพิมพ์ไปยังคอนโซลเพื่อจุดประสงค์ในการดีบั๊กมันถูกใช้เพื่อส่งผ่านไปยังฟังก์ชันอื่นที่ใช้ประเภทเป็นวัตถุ
Matt Bridges

2
OT: แปลกมากที่สวิฟท์ไม่ได้เสนอสิ่งนั้นนอกกรอบและใคร ๆ ก็ต้องเล่นซอกับไลบรารี C ระดับต่ำเช่นนี้ คุ้มค่าที่จะรายงานข้อผิดพลาดเหรอ?
qwerty_so

พวกฉันได้ให้คำตอบไว้ด้านล่าง โปรดดูและแจ้งให้เราทราบว่าเป็นสิ่งที่คาดหวัง
DILIP KOSURI

คำตอบ:


377

อัปเดตกันยายน 2559

Swift 3.0: การใช้type(of:)งานเช่นtype(of: someThing)(ตั้งแต่dynamicTypeลบคำค้นหาแล้ว)

อัปเดตตุลาคม 2558 :

ฉันปรับปรุงตัวอย่างด้านล่างนี้เพื่อสวิฟท์ใหม่ 2.0 ไวยากรณ์ (เช่นprintlnถูกแทนที่ด้วยprint, toString()อยู่ในขณะนี้String())

จากบันทึกประจำรุ่น Xcode 6.3 :

@nschum ชี้ให้เห็นในความคิดเห็นที่บันทึกย่อประจำรุ่น Xcode 6.3แสดงวิธีอื่น:

ค่า Type จะถูกพิมพ์เป็นชื่อประเภท demangled แบบเต็มเมื่อใช้กับ println หรือการแก้ไขสตริง

import Foundation

class PureSwiftClass { }

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")

print( "String(Int.self)           -> \(Int.self)")
print( "String((Int?).self         -> \((Int?).self)")
print( "String(NSString.self)      -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")

ผลลัพธ์ใด:

String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self)           -> Int
String((Int?).self         -> Optional<Int>
String(NSString.self)      -> NSString
String(Array<String>.self) -> Array<String>

อัพเดทสำหรับ Xcode 6.3:

คุณสามารถใช้_stdlib_getDemangledTypeName():

print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")

และรับสิ่งนี้เป็นผลลัพธ์:

TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String

คำตอบเดิม:

ก่อนหน้า Xcode 6.3 _stdlib_getTypeNameจะมีชื่อประเภท mangled ของตัวแปร รายการบล็อกของ Ewan Swickช่วยในการถอดรหัสสตริงเหล่านี้:

เช่น_TtSiย่อมาจากIntประเภทภายในของ Swift

ไมค์แอชมีรายการบล็อกที่ดีครอบคลุมหัวข้อเดียวกัน


2
คุณพบได้_stdlib_getTypeName()อย่างไร REPL แบบรวมไม่มีอยู่อีกต่อไปswift-ide-testไม่มีอยู่อย่างใดอย่างหนึ่งและการพิมพ์โมดูล Swift ของ Xcode จะ_เพิ่มค่าที่ได้รับการแก้ไข
Lily Ballard

10
ดูเหมือนว่าฉันสามารถค้นหาสัญลักษณ์ที่มีlldbได้ง่ายในแบบจำลอง นอกจากนี้ยังมีและ_stdlib_getDemangledTypeName() _stdlib_demangleName()
Lily Ballard

1
โอ้เรียบร้อยผมไม่ทราบเป็นทางลัดสำหรับimage target modulesฉันลงเอยด้วยการใช้target modules lookup -r -n _stdlib_ซึ่งแน่นอนว่าแสดงออกมาดีกว่าimage lookup -r -n _stdlib_ libswiftCore.dylib
Lily Ballard

1
FYI - ดูเหมือนว่า toString (... ) ถูกแทนที่ด้วย String (... )
Nick

6
Swift 3.0: dynamicTypeคำหลักถูกลบออกจาก Swift type(of:)มีการเพิ่มฟังก์ชันดั้งเดิมใหม่เข้าไปในภาษา: github.com/apple/swift/blob/master/CHANGELOG.md
Szu

46

แก้ไข: ใหม่toStringการทำงานได้รับการแนะนำในสวิฟท์ 1.2 (Xcode 6.3)

ตอนนี้คุณสามารถพิมพ์ประเภท demangled ของประเภทใดก็ได้โดยใช้.selfและตัวอย่างใด ๆ ที่ใช้.dynamicType:

struct Box<T> {}

toString("foo".dynamicType)            // Swift.String
toString([1, 23, 456].dynamicType)     // Swift.Array<Swift.Int>
toString((7 as NSNumber).dynamicType)  // __NSCFNumber

toString((Bool?).self)                 // Swift.Optional<Swift.Bool>
toString(Box<SinkOf<Character>>.self)  // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>>
toString(NSStream.self)                // NSStream

ลองโทรและYourClass.selfyourObject.dynamicType

อ้างอิง: https://devforums.apple.com/thread/227425


2
ฉันตอบไปที่หัวข้อนั้น แต่ฉันจะเพิ่มความคิดเห็นของฉันที่นี่ ค่าเหล่านั้นเป็นประเภท "Metatype" แต่ดูเหมือนจะไม่มีวิธีที่ง่ายที่จะเข้าใจว่าประเภทของวัตถุประเภท Metatype ซึ่งเป็นสิ่งที่ฉันกำลังมองหา
Matt Bridges

เป็นประเภท Metatype และเป็นคลาส พวกเขาเป็นตัวแทนของชั้นเรียน ไม่แน่ใจว่าปัญหาของคุณคืออะไร someInstance.dynamicType.printClassName()จะพิมพ์ชื่อของคลาส
ไฟล์อะนาล็อก

18
เมธอด printClassName () เป็นเพียงตัวอย่างเมธอดที่สร้างในตัวอย่างหนึ่งในเอกสารไม่ใช่การเรียก API ที่คุณสามารถเข้าถึงได้
เดฟวู้ด

4
FYI - ดูเหมือน toString (... ) ถูกแทนที่ด้วย String (... )
Nick

33

สวิฟท์ 3.0

let string = "Hello"
let stringArray = ["one", "two"]
let dictionary = ["key": 2]

print(type(of: string)) // "String"

// Get type name as a string
String(describing: type(of: string)) // "String"
String(describing: type(of: stringArray)) // "Array<String>"
String(describing: type(of: dictionary)) // "Dictionary<String, Int>"

// Get full type as a string
String(reflecting: type(of: string)) // "Swift.String"
String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>"
String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>"

1
การใช้งาน Swift 2 นั้นดีมากโดยเฉพาะกับกรณี enum ไม่มีใครรู้ว่าพฤติกรรมนี้เป็นเอกสาร / รับประกันโดย Apple? ห้องสมุดมาตรฐานเพียงรวมถึงความคิดเห็นที่ว่านี้เหมาะสำหรับการแก้จุดบกพร่อง ...
Milos

30

นี่คือสิ่งที่คุณกำลังมองหา?

println("\(object_getClassName(now))");

มันพิมพ์ "__NSDate"

อัปเดต : โปรดทราบว่าดูเหมือนว่าจะไม่ทำงานตั้งแต่ Beta05 อีกต่อไป


2
ไม่ทำงานกับคลาสที่รวดเร็ว ส่งคืน "UnsafePointer (0x7FBB18D06DE0)"
aryaxt

4
ไม่ทำงานกับคลาส ObjC (อย่างน้อยใน Beta5) สำหรับ NSManagedObject ฉันเพิ่งได้รับ "Builtin.RawPointer = ที่อยู่"
Kendall Helmstetter Gelner

23

Xcode ปัจจุบันของฉันคือเวอร์ชั่น 6.0 (6A280e)

import Foundation

class Person { var name: String; init(name: String) { self.name = name }}
class Patient: Person {}
class Doctor: Person {}

var variables:[Any] = [
    5,
    7.5,
    true,
    "maple",
    Person(name:"Sarah"),
    Patient(name:"Pat"),
    Doctor(name:"Sandy")
]

for variable in variables {
    let typeLongName = _stdlib_getDemangledTypeName(variable)
    let tokens = split(typeLongName, { $0 == "." })
    if let typeName = tokens.last {
        println("Variable \(variable) is of Type \(typeName).")
    }
}

เอาท์พุท:

Variable 5 is of Type Int.
Variable 7.5 is of Type Double.
Variable true is of Type Bool.
Variable maple is of Type String.
Variable Swift001.Person is of Type Person.
Variable Swift001.Patient is of Type Patient.
Variable Swift001.Doctor is of Type Doctor.

1
ดี แต่คำถามยังรวมถึงตัวเลือกมีการตั้งค่าเอาต์พุตของตัวเลือกOptional(...)ดังนั้นรหัสของคุณจะกลับมาOptionalเป็นประเภทเท่านั้น มันควรจะแสดงvar optionalTestVar: Person? = Person(name:"Sarah")เป็นตัวเลือก (คน) และ var กับบุคคล! เป็น ImplicitlyUnwrappedOptional (บุคคล)
Binarian

18

ตั้งแต่ Xcode 6.3 พร้อม Swift 1.2 คุณสามารถแปลงค่าของประเภทให้เป็น demangled ที่สมบูรณ์Stringได้

toString(Int)                   // "Swift.Int"
toString(Int.Type)              // "Swift.Int.Type"
toString((10).dynamicType)      // "Swift.Int"
println(Bool.self)              // "Swift.Bool"
println([UTF8].self)            // "Swift.Array<Swift.UTF8>"
println((Int, String).self)     // "(Swift.Int, Swift.String)"
println((String?()).dynamicType)// "Swift.Optional<Swift.String>"
println(NSDate)                 // "NSDate"
println(NSDate.Type)            // "NSDate.Type"
println(WKWebView)              // "WKWebView"
toString(MyClass)               // "[Module Name].MyClass"
toString(MyClass().dynamicType) // "[Module Name].MyClass"

เป็นไปได้ในทิศทางอื่นใน 1.2 หรือไม่? เพื่อเริ่มต้นอินสแตนซ์ตามชื่อคลาส?
965972

@ user965972 เท่าที่ฉันรู้ฉันไม่คิดว่ามี
kiding

17

คุณยังสามารถเข้าถึงชั้นเรียนผ่านclassName(ซึ่งส่งกลับค่า a String)

มีจริงหลายวิธีที่จะได้รับในชั้นเรียนนี้เป็นตัวอย่างเช่นclassForArchiver, classForCoder, classForKeyedArchiver(ทั้งหมดกลับมาAnyClass!)

คุณไม่สามารถรับชนิดของดึกดำบรรพ์ได้คลาส)

ตัวอย่าง:

var ivar = [:]
ivar.className // __NSDictionaryI

var i = 1
i.className // error: 'Int' does not have a member named 'className'

bridgeToObjectiveC()หากคุณต้องการที่จะได้รับชนิดของดั้งเดิมที่คุณต้องใช้ ตัวอย่าง:

var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber

ฉันเดิมพันมันเป็นแบบดั้งเดิม น่าเสียดายที่คุณไม่สามารถรับแบบดั้งเดิมได้
Leandros

ตัวอย่างเหล่านั้นดูเหมือนจะไม่ทำงานในสนามเด็กเล่น ฉันได้รับข้อผิดพลาดสำหรับดั้งเดิมและไม่เหมือนกัน
แมตต์บริดจ์

import Cocoaพยายามที่จะ
Leandros

9
className ดูเหมือนจะพร้อมใช้งานสำหรับ NSObjects เท่านั้นเมื่อพัฒนาสำหรับ OSX ไม่สามารถใช้งานได้ใน iOS SDK สำหรับวัตถุ NSObjects หรือ "ปกติ"
Matt Bridges

3
classNameเป็นส่วนหนึ่งของการสนับสนุน AppleScript ของ Cocoa และไม่ควรใช้เพื่อวิปัสสนาทั่วไป เห็นได้ชัดว่าไม่มีใน iOS
Nikolai Ruhe

16

คุณสามารถใช้ reflect เพื่อรับข้อมูลเกี่ยวกับวัตถุ
ตัวอย่างชื่อของคลาสอ็อบเจ็กต์:

var classname = สะท้อน (ตอนนี้) .summary

ใน Beta 6 นี่ทำให้ฉันมีชื่อแอพ + ชื่อคลาสในรูปแบบ mangled เล็กน้อย แต่เป็นการเริ่มต้น +1 สำหรับreflect(x).summary- ขอบคุณ!
Olie

ไม่ทำงานพิมพ์บรรทัดว่างใน Swift 1.2 Xcode 6.4 และ iOs 8.4
Juan Boero



10

ใน Xcode 8, Swift 3.0

ขั้นตอน:

1. รับประเภท:

ตัวเลือกที่ 1:

let type : Type = MyClass.self  //Determines Type from Class

ตัวเลือก 2:

let type : Type = type(of:self) //Determines Type from self

2. แปลง Type เป็น String:

let string : String = "\(type)" //String


7

สวิฟท์ 5

ด้วยการเปิดตัว Swift 3 ล่าสุดเราสามารถรับรายละเอียดของชื่อประเภทผ่านตัวตั้งStringค่าเริ่มต้นได้ print(String(describing: type(of: object)))เช่นยกตัวอย่างเช่น ซึ่งobject สามารถเป็นตัวแปรอินสแตนซ์เช่นอาร์เรย์, พจนานุกรมInt, a NSDate, อินสแตนซ์ของคลาสที่กำหนดเอง ฯลฯ

นี่คือคำตอบที่สมบูรณ์ของฉัน: รับชื่อคลาสของวัตถุเป็นสตริงใน Swift

คำถามที่กำลังมองหาวิธีการที่จะได้รับชื่อชั้นของวัตถุเป็นสตริง แต่ยังผมเสนออีกวิธีหนึ่งที่จะได้รับชื่อชั้นของตัวแปรที่ไม่ได้เป็น subclass NSObjectของ นี่มันคือ:

class Utility{
    class func classNameAsString(obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
}

ฉันทำฟังก์ชั่นคงที่ซึ่งใช้เป็นพารามิเตอร์วัตถุประเภทAnyและส่งกลับชื่อระดับเป็นString:)

ฉันทดสอบฟังก์ชันนี้ด้วยตัวแปรบางอย่างเช่น:

    let diccionary: [String: CGFloat] = [:]
    let array: [Int] = []
    let numInt = 9
    let numFloat: CGFloat = 3.0
    let numDouble: Double = 1.0
    let classOne = ClassOne()
    let classTwo: ClassTwo? = ClassTwo()
    let now = NSDate()
    let lbl = UILabel()

และผลลัพธ์คือ:

  • diccionary เป็นพจนานุกรมประเภท
  • Array เป็นประเภท Array
  • numInt เป็นประเภท Int
  • numFloat เป็นประเภท CGFloat
  • numDouble เป็นประเภท Double
  • classOne เป็นประเภท: ClassOne
  • classTwo เป็นประเภท: ClassTwo
  • ตอนนี้เป็นประเภท: วันที่
  • lbl เป็นประเภท: UILabel

5

เมื่อใช้ Cocoa (ไม่ใช่ CocoaTouch) คุณสามารถใช้classNameคุณสมบัติสำหรับวัตถุที่เป็นคลาสย่อยของ NSObject

println(now.className)

คุณสมบัตินี้ไม่พร้อมใช้งานสำหรับวัตถุ Swift ปกติซึ่งไม่ใช่คลาสย่อยของ NSObject (และในความเป็นจริงไม่มีรหัสประจำตัวหรือประเภทวัตถุใน Swift)

class Person {
    var name: String?
}

var p = Person()
println(person.className) // <- Compiler error

ใน CocoaTouch ในขณะนี้ไม่มีวิธีรับสตริงคำอธิบายประเภทของตัวแปรที่กำหนด ฟังก์ชั่นที่คล้ายกันนี้ไม่มีอยู่ในประเภทดั้งเดิมใน Cocoa หรือ CocoaTouch

Swift REPL สามารถพิมพ์สรุปค่ารวมถึงประเภทของมันดังนั้นจึงเป็นไปได้ที่วิธีการวิปัสสนานี้จะเป็นไปได้ผ่านทาง API ในอนาคต

แก้ไข : dump(object)ดูเหมือนว่าจะทำเคล็ดลับ


แม้แต่ในตอนของ Xcode 10 และ Swift 4.2 dump(object)ก็ยังทรงพลังจริงๆ ขอบคุณ.
Alex Zavatone

5

type(of:คำตอบด้านบนไม่ได้มีตัวอย่างการทำงานของวิธีการใหม่ของการทำเช่นนี้โดยใช้ ดังนั้นเพื่อช่วยมือใหม่อย่างฉันนี่คือตัวอย่างการทำงานซึ่งส่วนใหญ่นำมาจากเอกสารของ Apple ที่นี่ - https://developer.apple.com/documentation/swift/2885064-type

doubleNum = 30.1

func printInfo(_ value: Any) {
    let varType = type(of: value)
    print("'\(value)' of type '\(varType)'")
}

printInfo(doubleNum)
//'30.1' of type 'Double'

4

ฉันได้ลองคำตอบอื่น ๆ ที่นี่ แต่ระยะทางดูเหมือนจะเป็นอย่างมากกับสิ่งที่เป็นลูกน้อง

อย่างไรก็ตามฉันพบวิธีที่คุณสามารถรับชื่อคลาส Object-C สำหรับวัตถุโดยทำต่อไปนี้:

now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for

นี่คือตัวอย่างวิธีการใช้งาน:

let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")

ในกรณีนี้มันจะพิมพ์ NSDate ในคอนโซล


4

ฉันพบโซลูชันนี้ซึ่งหวังว่าอาจใช้ได้ผลกับคนอื่น ฉันสร้างวิธีการเรียนเพื่อเข้าถึงค่า โปรดจำไว้ว่าสิ่งนี้จะใช้ได้กับคลาสย่อยของ NSObject เท่านั้น แต่อย่างน้อยก็เป็นวิธีที่สะอาดและเป็นระเบียบ

class var className: String!{
    let classString : String = NSStringFromClass(self.classForCoder())
    return classString.componentsSeparatedByString(".").last;
}

4

ใน XCode 6.3 ล่าสุดกับ Swift 1.2 นี่เป็นวิธีเดียวที่ฉันค้นพบ:

if view.classForCoder.description() == "UISegment" {
    ...
}

หมายเหตุ: description () ส่งคืนชื่อคลาสในรูปแบบ<swift module name>.<actual class name>ดังนั้นคุณต้องการแยกสตริงด้วย.และรับโทเค็นสุดท้าย
Matthew Quiros

4

คำตอบมากมายที่นี่ไม่สามารถใช้ได้กับ Swift รุ่นล่าสุด (Xcode 7.1.1 ในขณะที่เขียน)

วิธีการรับข้อมูลในปัจจุบันคือการสร้างMirrorและสอบถามว่า สำหรับ classname มันง่ายเหมือน:

let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description

Mirrorข้อมูลเพิ่มเติมเกี่ยวกับวัตถุที่ยังสามารถเรียกดูได้จาก ดูhttp://swiftdoc.org/v2.1/type/Mirror/สำหรับรายละเอียด


ผิดกับคำตอบอะไรstackoverflow.com/a/25345480/1187415และstackoverflow.com/a/32087449/1187415 ? ทั้งสองดูเหมือนจะทำงานค่อนข้างดีกับสวิฟท์ 2 (ยังไม่ได้ตรวจสอบคนอื่น ๆ .)
มาร์ติน R

ฉันชอบสิ่งนี้เป็นวิธีแก้ปัญหาทั่วไป แต่การได้รับ "Mirror for ViewController" (ภายนอก "Mirror for") - รอดูเหมือนว่าใช้ ".ubjectType" ทำเคล็ดลับ!
David H

3

ใน lldb ตั้งแต่ beta 5 คุณสามารถดูคลาสของวัตถุด้วยคำสั่ง:

fr v -d r shipDate

ซึ่งแสดงผลเช่น:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

คำสั่งที่ขยายออกหมายถึงสิ่งที่ชอบ:

Frame Variable (พิมพ์ตัวแปรเฟรม) -d run_target (ขยายประเภทไดนามิก)

สิ่งที่มีประโยชน์ที่ควรทราบคือการใช้ "Frame Variable" เพื่อส่งออกค่าตัวแปรรับประกันว่าจะไม่มีการใช้รหัส


3

ฉันพบวิธีแก้ปัญหาสำหรับชั้นเรียนที่พัฒนาตนเอง (หรือคุณสามารถเข้าถึง)

วางคุณสมบัติที่คำนวณต่อไปนี้ภายในนิยามคลาสอ็อบเจ็กต์ของคุณ:

var className: String? {
    return __FILE__.lastPathComponent.stringByDeletingPathExtension
}

ตอนนี้คุณสามารถเรียกชื่อคลาสบนวัตถุของคุณได้ดังนี้

myObject.className

โปรดทราบว่านี่จะใช้งานได้หากคำจำกัดความของคลาสของคุณถูกสร้างขึ้นภายในไฟล์ที่มีชื่อตรงเช่น class ที่คุณต้องการชื่อของ

เช่นนี้เป็นกันมากในกรณีที่คำตอบข้างต้นควรจะทำมันสำหรับกรณีส่วนใหญ่ แต่ในบางกรณีคุณอาจจำเป็นต้องหาทางออกที่แตกต่างออกไป


หากคุณต้องการชื่อคลาสภายในคลาส (ไฟล์)คุณสามารถใช้บรรทัดนี้ได้โดยง่าย:

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

บางทีวิธีนี้อาจช่วยให้บางคนออกไปที่นั่น


3

จากคำตอบและความคิดเห็นของ Klass และ Kevin Ballard ด้านบนฉันจะไปกับ:

println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!)

println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!)

ซึ่งจะพิมพ์ออกมา:

"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"

"NSString"
"PureSwiftClass"
"Int"
"Double"

ฉันคิดว่านี่เป็นคำตอบที่ดีกว่า
maschall

ฉันลงเอยด้วยการใช้ใน Swift 1.2 ต่อไปนี้: toString(self.dynamicType).componentsSeparatedByString(".").last!เห็นได้ชัดว่าฉันอยู่ในบริบทของวัตถุและสามารถอ้างอิงselfได้
Joe

3
let i: Int = 20


  func getTypeName(v: Any) -> String {
    let fullName = _stdlib_demangleName(_stdlib_getTypeName(i))
    if let range = fullName.rangeOfString(".") {
        return fullName.substringFromIndex(range.endIndex)
    }
    return fullName
}

println("Var type is \(getTypeName(i)) = \(i)")


3

สวิฟท์ 4:

// "TypeName"
func stringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(describing: some) : String(describing: type(of: some))
    return string
}

// "ModuleName.TypeName"
func fullStringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(reflecting: some) : String(reflecting: type(of: some))
    return string
}

การใช้งาน:

print(stringType(of: SomeClass()))     // "SomeClass"
print(stringType(of: SomeClass.self))  // "SomeClass"
print(stringType(of: String()))        // "String"
print(fullStringType(of: String()))    // "Swift.String"

2

ดูเหมือนจะไม่มีวิธีทั่วไปในการพิมพ์ชื่อประเภทของประเภทของค่าโดยพลการ ดังที่คนอื่นได้กล่าวไว้สำหรับอินสแตนซ์ของคลาสที่คุณสามารถพิมพ์ได้value.classNameแต่สำหรับค่าดั้งเดิมนั้นปรากฏว่าเมื่อรันไทม์ข้อมูลประเภทจะหายไป

ยกตัวอย่างเช่นมันดูราวกับว่ามีไม่วิธีการพิมพ์: 1.something()และได้รับการออกค่าใดIntsomething(คุณสามารถเป็นคำตอบอื่นแนะนำการใช้งานi.bridgeToObjectiveC().classNameที่จะให้คำแนะนำ แต่__NSCFNumberเป็นไม่จริงชนิดของi-. เพียงแค่สิ่งที่มันจะถูกแปลงเป็นเมื่อมันข้ามขอบเขตของการเรียกใช้ฟังก์ชันวัตถุประสงค์ซี)

ฉันยินดีที่จะได้รับการพิสูจน์ผิด แต่ดูเหมือนว่าการตรวจสอบประเภทเสร็จสิ้นในเวลารวบรวมและเช่น C ++ (เมื่อปิดใช้งาน RTTI) ข้อมูลประเภทส่วนใหญ่จะหายไปในขณะทำงาน


คุณสามารถยกตัวอย่างการใช้ className เพื่อพิมพ์ "NSDate" สำหรับตัวแปร "ตอนนี้" ในตัวอย่างของฉันที่ใช้งานได้ในสนามเด็กเล่นของ Xcode6 หรือไม่ เท่าที่ฉันสามารถบอกได้ className ไม่ได้ถูกกำหนดไว้ในวัตถุ Swift แม้เป็น subclasses ของ NSObject
Matt Bridges

ปรากฏว่า 'className' พร้อมใช้งานสำหรับวัตถุที่สืบทอดจาก NSObject แต่เฉพาะเมื่อพัฒนาสำหรับ mac ไม่ใช่สำหรับ iOS ดูเหมือนจะไม่มีวิธีแก้ไขทั้งหมดสำหรับ iOS
Matt Bridges

1
ใช่ของจริงที่นี่ดูเหมือนว่าในกรณีทั่วไปข้อมูลประเภทจะหายไปอย่างรวดเร็ว
ipmcc

ฉันสงสัยว่า REPL สามารถพิมพ์ประเภทของค่าได้อย่างไร
Matt Bridges

REPL ถูกตีความเกือบจะแน่นอนและไม่ได้รวบรวมซึ่งจะอธิบายได้อย่างง่ายดาย
ipmcc

2

นี่คือวิธีที่คุณได้รับสตริงประเภทของวัตถุหรือชนิดที่สอดคล้องและคำนึงถึงโมดูลที่คำจำกัดความของวัตถุเป็นของหรือซ้อนกันทำงานใน Swift 4.x

@inline(__always) func typeString(for _type: Any.Type) -> String {
    return String(reflecting: type(of: _type))
}

@inline(__always) func typeString(for object: Any) -> String {
    return String(reflecting: type(of: type(of: object)))
}

struct Lol {
    struct Kek {}
}

// if you run this in playground the results will be something like
typeString(for: Lol.self)    //    __lldb_expr_74.Lol.Type
typeString(for: Lol())       //    __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)//    __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek())   //    __lldb_expr_74.Lol.Kek.Type

2

ในการรับชนิดของวัตถุหรือคลาสของวัตถุในSwiftคุณต้องใช้ชนิด (จาก: yourObject)

ประเภท (จาก: yourObject)


1

ไม่ใช่สิ่งที่คุณเป็นหลังจากนั้น แต่คุณสามารถตรวจสอบประเภทของตัวแปรเทียบกับประเภท Swift เช่น:

let object: AnyObject = 1

if object is Int {
}
else if object is String {
}

ตัวอย่างเช่น.


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.