আপনি কীভাবে কোনও বস্তুর প্রকারটি আবিষ্কার করতে পারেন (সুইফটে)?


255

কোনও প্রোগ্রাম বোঝার চেষ্টা করার সময়, বা কোনও কোনও কোণে, আসলে কী ধরণের তা আসলে খুঁজে পেতে সক্ষম হওয়া দরকারী useful আমি জানি যে ডিবাগার আপনাকে কিছু প্রকারের তথ্য প্রদর্শন করতে পারে এবং আপনি সাধারণত সেই ধরণের পরিস্থিতি উল্লেখ না করে পালিয়ে যাওয়ার জন্য টাইপ অনুক্রমের উপর নির্ভর করতে পারেন, তবে তবুও আমি সত্যই পাইথনের মতো কিছু পেতে চাইtype()

ডায়নামিক টাইপ ( এই প্রশ্নটি দেখুন )

আপডেট: এটি সুইফটের সাম্প্রতিক সংস্করণে পরিবর্তিত হয়েছে, obj.dynamicTypeএখন আপনি টাইপটির জন্য একটি রেফারেন্স দেয়, গতিশীল টাইপের উদাহরণ নয়।

এটি একটি সবচেয়ে প্রতিশ্রুতিবদ্ধ বলে মনে হয়, তবে এখনও পর্যন্ত আমি আসল ধরণটি সন্ধান করতে পারিনি

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self

আমি কোনও নতুন অবজেক্টটি ইনস্ট্যান্ট করতে ক্লাসের রেফারেন্সটি ব্যবহার করার চেষ্টাও করেছি, যা কাজ করে তবে অদ্ভুতভাবে আমাকে ত্রুটি দিয়েছিল যে আমাকে অবশ্যই একটি requiredআরম্ভকারী অবশ্যই যুক্ত করতে হবে :

কাজ করে:

class MyClass {
    var count = 0
    required init() {
    }
}

let myClass2 = MyClass.self
let mc2 = MyClass2()

এখনও কোনও প্রদত্ত বস্তুর প্রকারটি আবিষ্কার করার দিকে কেবল একটি ছোট পদক্ষেপ

সম্পাদনা : আমি এখন যথেষ্ট অপ্রাসঙ্গিক বিবরণ সরিয়েছি - আপনার আগ্রহী হলে সম্পাদনার ইতিহাস দেখুন :)



1
আকর্ষণীয়ভাবে, print(mc)বা dump(mc)একটি সারাংশ (যা থেকে আপনি পেতে পারেন toString(mc)বা reflect(mc).summary) মুদ্রণ করবে, এতে কোথাও কোথাও শ্রেণীর নাম থাকবে। তবে কীভাবে নিজের নিজের ক্লাসের নাম পাবেন তা পরিষ্কার নয়।
newacct

@ ডেভিড অনুরূপ, তবে সমস্ত ভেরিয়েবল শ্রেণীর দৃষ্টান্ত নয়। এছাড়াও যে প্রশ্নগুলি প্রোগ্রামারটি যা খুঁজছিল তার সাথে মেলে কিনা তা যাচাই করা ছিল, আমি কেবল এই ধরণের
পাইকারটি


উত্তর:


284

সুইফট 3 সংস্করণ:

type(of: yourObject)

8
মজার ব্যাপার. এটি সুস্পষ্টভাবে মোড়কযুক্ত বিকল্পগুলির সাথে কাজ করে না! অর্থাত var myVar: SomeType!। সংকলক ত্রুটিটি দেয় "টাইপটির 'কিছু ধরণের টাইপ' রূপান্তর করতে পারে না! 'টাইপ' (ওরফে 'ইম্প্রেলিউইনপ্রেডঅপশনাল <সুমাইটাইপ>। টাইপ') প্রত্যাশিত আর্গুমেন্ট টাইপ 'যেকোনক্লাস' (ওরফে 'AnyObject.Type') রূপান্তরকারী as! AnyClassটাইপের পরে যোগ করার পরামর্শ দেয় তবে তারপরে প্রোগ্রামটি কিছু "EXC_BAD_INSTRUCTION" এবং অন্যান্য জিবেরিশের সাথে ক্র্যাশ হয়েছে যা আমি সিদ্ধান্ত নিতে পারি না
লাইটনিংস্ট্রিট

1
আসলে, এটি এখনই গ্রহণযোগ্য উত্তর হওয়া উচিত যে সুইফট 3 বিদ্যমান। ধন্যবাদ জেরেমি!
বায়োমিকার

1
আপনি যদি সুনির্দিষ্ট টাইপের নাম খুঁজছেন, যখন প্রকারটি প্রোটোকল টাইপের হয়, এটি আপনার পক্ষে কাজ নাও করতে পারে।
ক্রিস প্রিন্স

2
আপনার যদি Stringএমন থাকে যা টাইপ হিসাবে পাস হয় Anyতবে type(of:)আউটপুট আসবে Any, না String
স্কটিব্ল্যাডেস

1
@ স্কটিব্ল্যাডস তাই এর সমাধান কী হবে। আপনি সরবরাহ করতে পারেন?
মুবিন মল

109

সুইফট ২.০:

এই জাতীয় প্রকারের আত্মপরিচয়টি করার সঠিক উপায়টি মিরর স্ট্রাক্টের সাথে থাকবে ,

    let stringObject:String = "testing"
    let stringArrayObject:[String] = ["one", "two"]
    let viewObject = UIView()
    let anyObject:Any = "testing"

    let stringMirror = Mirror(reflecting: stringObject)
    let stringArrayMirror = Mirror(reflecting: stringArrayObject)
    let viewMirror = Mirror(reflecting: viewObject)
    let anyMirror = Mirror(reflecting: anyObject)

তারপরে Mirrorস্ট্রাক্ট থেকে নিজেই টাইপ অ্যাক্সেস করতে আপনি এই জাতীয় সম্পত্তিটি ব্যবহার করবেন subjectType:

    // Prints "String"
    print(stringMirror.subjectType)

    // Prints "Array<String>"
    print(stringArrayMirror.subjectType)

    // Prints "UIView"
    print(viewMirror.subjectType)

    // Prints "String"
    print(anyMirror.subjectType)

এরপরে আপনি এর মতো কিছু ব্যবহার করতে পারেন:

    if anyMirror.subjectType == String.self {
        print("anyObject is a string!")
    } else {
        print("anyObject is not a string!")
    }

7
এটা অসাধারণ. সাবধান থাকুন যে বিষয়টিকে মিরর করা হচ্ছে তা alচ্ছিক ধরণের হয়, তবে এটি একটি অ-alচ্ছিক প্রকারের সাথে তুলনা করা ব্যর্থ হবে। Stringএবং Optional(String)এক নয়।
টমাস ভারবেক

1
ঠিক আমি যা খুঁজছিলাম, অবজেক্টের
জোসেফ

এই প্রসঙ্গে কি এমন কোনও তুলনা রয়েছে যা অ-alচ্ছিক প্রকারের সাথে alচ্ছিক তুলনা করার সময় ব্যর্থ হবে না ?
ক্রিস প্রিন্স

এটাই আমি খুঁজছিলাম। আপনাকে ধন্যবাদ গুডবার্গুর।
মুবিন মল

60

dynamicType.printClassNameকোড সুইফট বইয়ে একটি উদাহরণ থেকে। সরাসরি কোনও কাস্টম শ্রেণীর নাম দখল করার আমি জানার উপায় নেই তবে isনীচের চিত্রের মতো আপনি কীওয়ার্ডটি ব্যবহার করে একটি উদাহরণ টাইপ পরীক্ষা করতে পারেন । এই উদাহরণটি দেখায় যে কীভাবে একটি কাস্টম ক্লাসনেম ফাংশন বাস্তবায়ন করতে হবে, যদি আপনি সত্যিকার অর্থে স্ট্রিং হিসাবে শ্রেণীর নাম চান।

class Shape {
    class func className() -> String {
        return "Shape"
    }
}

class Square: Shape {
    override class func className() -> String {
        return "Square"
    }
}

class Circle: Shape {
    override class func className() -> String {
        return "Circle"
    }
}

func getShape() -> Shape {
    return Square() // hardcoded for example
}

let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true

দ্রষ্টব্য:
যে সাবক্লাসগুলি NSObjectইতিমধ্যে তাদের নিজস্ব ClassName ফাংশন বাস্তবায়ন করে। আপনি যদি কোকো দিয়ে কাজ করছেন তবে আপনি কেবল এই সম্পত্তিটি ব্যবহার করতে পারেন।

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()

2
আরে, কখন পরিবর্তন হয়েছিল তা নিশ্চিত নন, তবে অ্যালেক্স প্রেটজ্লাভ যেমন উল্লেখ করেছেন, আচরণ বদলেছে।
জিয়াআরো

1
হ্যাঁ. সুইফট ৩.০ হিসাবে, subjectTypeআর উপলভ্য নয় এবং dynamicTypeএটি সংকলক থেকে অবহেলা বার্তা দেয়।
রাফেল

41

এক্সকোড 6.0.1 হিসাবে (কমপক্ষে, তারা এটি যুক্ত করার পরে নিশ্চিত নয়), আপনার আসল উদাহরণটি এখন কাজ করে:

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`

হালনাগাদ:

মূল প্রশ্নের উত্তর দিতে, আপনি আসলে সাফল্য সুইফট অবজেক্টগুলি সাফল্যের সাথে অবজেক্ট-সি রানটাইম ব্যবহার করতে পারেন।

নিম্নলিখিত চেষ্টা করুন:

import Foundation
class MyClass { }
class SubClass: MyClass { }

let mc = MyClass()
let m2 = SubClass()

// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))

দেখে মনে হচ্ছে কোনও উদাহরণের পরিবর্তে টাইপটি দেওয়ার জন্য তারা এটিকে পরিবর্তন করেছে।
জিয়াআরো

@ জিয়ারো, আমি আমার উত্তরটি আপডেট করেছিলাম যা আমি মনে করি যে আপনি আপনার মূল প্রশ্নটি সন্ধান করেছেন
অ্যালেক্স প্রেটজলাভ

36

আপনার যদি ভেরিয়েবলটি X প্রকারের, বা এটি কোনও প্রোটোকলের সাথে সামঞ্জস্যপূর্ণ কিনা তা খতিয়ে দেখতে প্রয়োজন, তবে আপনি ব্যবহার করতে পারেন isবা as?নীচের মত:

var unknownTypeVariable =if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}

এটি isKindOfClassওবজে-সি এর সমতুল্য ।

এবং এটি conformsToProtocol, বা এর সমতুল্যisMemberOfClass

var unknownTypeVariable =if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
    //unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
    //unknownTypeVariable is not of type <ClassName or ProtocolName>
}

আপনার উত্তরের দ্বিতীয় অংশটি ভুল। as?শর্তসাপেক্ষ কাস্ট সহ "যদি চলুন" বিবৃতিটি একই কাজ isKindOfClassকরে তবে এটি সফল হওয়ার পরেও কাস্টের ফলাফল সরবরাহ করে।
অহলফ

এর সমতুল্য isMemberOfClassশর্ত object.dynamicType == ClassName.self
অজল্ফ


10

সুইফট 3.0 এর জন্য

String(describing: <Class-Name>.self)

সুইফট ২.০ - ২.৩ এর জন্য

String(<Class-Name>)

1
এই উত্তরটি আমার পক্ষে সঠিক হওয়া সম্পর্কে গুরুত্বপূর্ণ বিষয়টি হ'ল ফলস্বরূপ স্ট্রিংটি ক্লাসের নামের সাথে ঠিক মিলে যায় - সুতরাং আমি এনএসম্যানেজডঅবজেক্ট সাবক্লাস থেকে একটি কোর ডেটার সত্তার নাম পেতে এটি ব্যবহার করতে পারি। আমি সুইফট 3 সংস্করণ ব্যবহার করেছি।
কেন্ডল হেলস্টেটার জেলনার

8

এটি করার জন্য আমি এখানে দুটি উপায় প্রস্তাব করছি:

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")
}

2
print( aShape is Square ), isঅপারেটর আরো বাঞ্ছনীয়।
ডনসং

ধরণের জিনিস পেতে আমার পক্ষে ভাল সমাধান।
নিহস্মাত

1

ব্যবহারের ক্ষেত্রে নির্ভর করে। তবে ধরে নেওয়া যাক আপনি আপনার "ভেরিয়েবল" প্রকারের সাথে দরকারী কিছু করতে চান। সুইফট switchবিবৃতিটি খুব শক্তিশালী এবং আপনি যে ফলাফলগুলি সন্ধান করছেন তা পেতে সহায়তা করতে পারে ...

    let dd2 = ["x" : 9, "y" : "home9"]
    let dds = dd2.filter {
        let eIndex = "x"
        let eValue:Any = 9
        var r = false

        switch eValue {
        case let testString as String:
            r = $1 == testString
        case let testUInt as UInt:
            r = $1 == testUInt
        case let testInt as Int:
            r = $1 == testInt
        default:
            r = false
        }

        return r && $0 == eIndex
    }

এই ক্ষেত্রে, একটি সাধারণ অভিধান থাকে যাতে কী / মান জোড়া থাকে যা ইউআইএনটি, ইন্ট বা স্ট্রিং হতে পারে। ইন .filter()অভিধানে পদ্ধতি, আমি সঠিকভাবে মূল্যবোধ ও স্ট্রিং শুধুমাত্র পরীক্ষার জন্য নিশ্চিত আমি পরীক্ষা করতে হবে যখন এটি একটি স্ট্রিং এর ইত্যাদি সুইচ বিবৃতি এই সহজ এবং নিরাপদ করে তোলে! যেকোন প্রকারের ভেরিয়েবলে 9 নিয়োগের মাধ্যমে এটি ইন্টের এক্সিকিউট করতে সক্ষম হয়। এটিকে পরিবর্তন করার চেষ্টা করুন:

   let eValue:Any = "home9"

.. এবং আবার চেষ্টা করুন। এবার as Stringমামলাটি কার্যকর করে।


1

যদি আপনি একটি "সর্বদা সত্য / ব্যর্থ" সতর্কতা পান তবে ব্যবহারের আগে আপনাকে যে কোনওটিতে কাস্ট করতে হবে is

(foo as Any) is SomeClass

0
//: Playground - noun: a place where people can play

import UIKit

class A {
    class func a() {
        print("yeah")
    }

    func getInnerValue() {
        self.dynamicType.a()
    }
}

class B: A {
    override class func a() {
        print("yeah yeah")
    }
}

B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.