একটি ফাংশন প্যারামিটার হিসাবে কোনও শ্রেণীর ধরণ কীভাবে পাস করতে হয়


146

আমার একটি জেনেরিক ফাংশন রয়েছে যা একটি ওয়েব পরিষেবাতে কল করে এবং কোনও জিনিসে জেএসএন প্রতিক্রিয়াটিকে সিরিয়ালাইজ করে।

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {

            /* Construct the URL, call the service and parse the response */
}

আমি যা সম্পাদন করার চেষ্টা করছি তা হ'ল এই জাভা কোডের সমতুল্য

public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
                               final Class<T> classTypeToReturn) {
}
  • আমি সঠিক অর্জনের চেষ্টা করছি তার জন্য কি আমার পদ্ধতির স্বাক্ষর রয়েছে?
  • আরও সুনির্দিষ্টভাবে, AnyClassকোনও পরামিতি টাইপ করার জন্য সঠিক জিনিসটি করা হচ্ছে?
  • পদ্ধতিটি কল করার সময়, আমি MyObject.selfরিটার্নিং ক্লাস মান হিসাবে পাস করছি তবে আমি একটি সংকলন ত্রুটি পেয়েছি "" স্ট্রিং "টাইপ করতে এক্সপ্রেশনটির টাইপ '()' রূপান্তর করতে পারি না"
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/

}

সম্পাদনা:

আমি object_getClassহোলএলএক্স দ্বারা উল্লিখিত হিসাবে ব্যবহার করার চেষ্টা করেছি, কিন্তু এখন আমি পেয়েছি:

ত্রুটি: "'সিটিআইএনফো টাইপ করুন' টাইপ প্রোটোকল 'যেকোনওবজেক্ট' এর সাথে মানায় না"

প্রোটোকল অনুসারে কি করা দরকার?

class CityInfo : NSObject {

    var cityName: String?
    var regionCode: String?
    var regionName: String?
}

আমি মনে করি না যে সুইফট জেনেরিকগুলি জাভাগুলির মতো কাজ করে। সুতরাং অনুমানকারী যে বুদ্ধিমান হতে পারে না। আইডি ক্লাস বাদ দিন <T> জিনিসটি জেনেরিক CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
ক্রিশ্চান ডায়েট্রিচ

উত্তর:


144

আপনি এটি ভুল উপায়ে পৌঁছে যাচ্ছেন: সুইফটে, অবজেক্টিভ-সি-এর বিপরীতে, ক্লাসগুলির নির্দিষ্ট ধরণের রয়েছে এবং এমনকি একটি উত্তরাধিকারের শ্রেণিবদ্ধতা রয়েছে (এটি যদি শ্রেণিটি Bউত্তরাধিকার সূত্রে প্রাপ্ত হয় Aতবে এর B.Typeথেকেও উত্তরাধিকার সূত্রে প্রাপ্ত হয় A.Type):

class A {}
class B: A {}
class C {}

// B inherits from A
let object: A = B()

// B.Type also inherits from A.Type
let type: A.Type = B.self

// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self

এ কারণেই আপনার ব্যবহার করা উচিত নয় AnyClass, যদি না আপনি সত্যিই কোনও শ্রেণীর অনুমতি দিতে চান । এই ক্ষেত্রে সঠিক ধরণ হবে T.Typeকারণ এটি returningClassপ্যারামিটার এবং বন্ধের প্যারামিটারের মধ্যে লিঙ্কটি প্রকাশ করে ।

আসলে, পরিবর্তে এটি ব্যবহার করে AnyClassসংকলকটি পদ্ধতি কলের মধ্যে সঠিকভাবে অনুমান করতে দেয়:

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
    // The compiler correctly infers that T is the class of the instances of returningClass
    handler(returningClass())
}

Tপাস করার একটি উদাহরণ তৈরির ক্ষেত্রে এখন সমস্যা আছে handler: আপনি এখনই কোডটি চেষ্টা করে চালান এবং সংকলকটি অভিযোগ করবে যেটি গঠনযোগ্য Tনয় ()। এবং যথাযথভাবে তাই: Tএটি একটি নির্দিষ্ট আরম্ভকারী প্রয়োগ করে তা প্রয়োজন স্পষ্টভাবে সীমাবদ্ধ করতে হবে।

এটি নীচের মত একটি প্রোটোকল দিয়ে করা যেতে পারে:

protocol Initable {
    init()
}

class CityInfo : NSObject, Initable {
    var cityName: String?
    var regionCode: String?
    var regionName: String?

    // Nothing to change here, CityInfo already implements init()
}

তারপরে আপনাকে কেবল জেনেরিক সীমাবদ্ধতা invokeServiceথেকে অন্যটিতে পরিবর্তন <T>করতে হবে <T: Initable>

ডগা

যদি আপনি "স্ট্রিং" টাইপ করতে "এক্সপ্রেশনটির টাইপ '()' র রূপান্তর করতে পারবেন না" এর মতো অদ্ভুত ত্রুটিগুলি পান তবে পদ্ধতি কলের প্রতিটি যুক্তি তার নিজস্ব ভেরিয়েবলে স্থানান্তর করতে প্রায়শই কার্যকর। এটি কোডটি সংকীর্ণ করতে সহায়তা করে যা ত্রুটি সৃষ্টি করছে এবং প্রকারের আনফারিংয়ের সমস্যাটি উদঘাটন করছে:

let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self

CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/

}

ভেরিয়েবল এক এরর প্যাচসমূহ (যার মানে ভুল অংশ আছে) অথবা তোমার মত "অভিব্যক্তি ধরন রূপান্তর করা যায় না একটি রহস্যপূর্ণ বার্তা পাবেন: এখন সেখানে দুটি সম্ভাবনা আছে ()টাইপ করতে ($T6) -> ($T6) -> $T5"।

পরবর্তী ত্রুটির কারণ হ'ল সংকলকটি আপনি যা লিখেছেন তার ধরণগুলি নির্ধারণ করতে সক্ষম হয় না। এক্ষেত্রে সমস্যাটি হ'ল Tকেবল বন্ধের প্যারামিটারে ব্যবহৃত হয় এবং আপনি যে ক্লোজারটি পেরিয়েছিলেন তা কোনও নির্দিষ্ট ধরণের নির্দেশ দেয় না তাই সংকলকটি কোন প্রকারটি নির্ধারণ করতে পারে তা জানে না। returningClassঅন্তর্ভুক্ত করার ধরণটি পরিবর্তন করে Tআপনি সংকলকটিকে জেনেরিক পরামিতি নির্ধারণের জন্য একটি উপায় দেন।


টি টাইপ ইঙ্গিতটির জন্য ধন্যবাদ - আর্গুমেন্ট হিসাবে ক্লাসের ধরণটি পাস করার জন্য আমার যা প্রয়োজন।
এচেলন

শেষে "টিপ" আমাকে বাঁচিয়েছিল
অ্যালেক্স

কোনও <টি: অনিবার্য> টেম্পলেটড ফাংশনটি ব্যবহার করার পরিবর্তে রিটার্নিংক্লাসকে ইনিয়েটেবল হিসাবে পাস করাও সম্ভব T টাইপ
ডিভাস

মূল কোডে যা বিভিন্ন ফলাফল তৈরি করে। জেনেরিক পরামিতি Tব্যবহার করা returningClassবস্তুর এবং এর মধ্যবর্তী সম্পর্কের প্রকাশ করতে ব্যবহৃত হয় completionHandler। যদি Initiable.Typeব্যবহার হয় তবে এই সম্পর্কটি নষ্ট হয়ে যায়।
এলিয়াকারেদা

এবং? জেনারিকস লিখতে দেয় নাfunc somefunc<U>()
গার্গো

34

আপনি AnyObjectএই মাধ্যমে ক্লাস পেতে পারেন :

সুইফট 3.x

let myClass: AnyClass = type(of: self)

সুইফট 2.x

let myClass: AnyClass = object_getClass(self)

আপনি যদি চান তবে পরে এটি প্যারামিটার হিসাবে পাস করতে পারেন।


1
self.dynamicType
আপনিও

1
। যখনই আমি এটা myClass "" অঘোষিত ধরনের ব্যবহার "এর একটি ত্রুটি মেশে myClass ব্যবহারের চেষ্টা সুইফট 3, সর্বশেষ Xcode এবং iOS এর তৈরী করে
বিভ্রান্ত

@ কনফিউজড, আমি এর সাথে এ জাতীয় কোনও সমস্যা দেখছি না, আপনাকে প্রসঙ্গ সম্পর্কে আরও তথ্য দেওয়ার দরকার হতে পারে।
হোলএক্স

আমি একটি বোতাম তৈরি করছি। সেই বোতামের কোডে (এটি স্প্রিটকিট, সুতরাং স্পর্শবিগনের অভ্যন্তরে) আমি বোতামটি ক্লাস ফাংশন কল করতে চাই, সুতরাং সেই শ্রেণীর একটি রেফারেন্স প্রয়োজন। বাটন ক্লাসে আমি ক্লাসের রেফারেন্স রাখতে একটি পরিবর্তনশীল তৈরি করেছি have তবে আমি এটি কোনও ক্লাস, বা টাইপটি যে শ্রেণিটি হ'ল সঠিক শব্দচয়ন / পরিভাষা যাই হোক না কেন পেতে পারি না। আমি এটি কেবলমাত্র উদাহরণগুলির জন্য রেফারেন্স সঞ্চয় করতে পারি। সাধারণত, আমি ক্লাস প্রকারের একটি রেফারেন্সটি বোতামে পাস করতে চাই। তবে আমি সবেমাত্র একটি অভ্যন্তরীণ রেফারেন্স তৈরি করে শুরু করেছি এবং এমনকি এটির কাজও করতে পারি নি।
বিভ্রান্ত

এটি পদ্ধতি এবং চিন্তাভাবনার একটি ধারাবাহিকতা ছিল যা আমি এখানে ব্যবহার করছি: stackoverflow.com/questions/41092440/… । আমি তখন থেকে প্রোটোকল নিয়ে কাজ করার কিছু যুক্তি অর্জন করেছি, তবে দ্রুততার সাথে সামনে আসার সাথে সাথে আমি আরও সহজ পদ্ধতিগুলির সাথে কী করতে পারি বলে ভেবেছিলাম তার জন্য প্রয়োজনীয় প্রকার ও জেনেরিকগুলিও বের করতে হবে। বা কেবল চারপাশে প্রচুর কোড অনুলিপি করুন এবং আটকান। যা আমি সাধারণত করি;)
বিভ্রান্ত

7

আমার কাছে সুইফট 5 তেও একই ব্যবহারের ঘটনা রয়েছে:

class PlistUtils {

    static let shared = PlistUtils()

    // write data
    func saveItem<T: Encodable>(url: URL, value: T) -> Bool{
        let encoder = PropertyListEncoder()
        do {
            let data = try encoder.encode(value)
            try data.write(to: url)
            return true
        }catch {
            print("encode error: \(error)")
            return false
        }
    }

    // read data

    func loadItem<T: Decodable>(url: URL, type: T.Type) -> Any?{
        if let data = try? Data(contentsOf: url) {
            let decoder = PropertyListDecoder()
            do {
                let result = try decoder.decode(type, from: data)
                return result
            }catch{
                print("items decode failed ")
                return nil
            }
        }
        return nil
    }

}

আমি অনুরূপ কিছু করতে চেষ্টা করছি, কিন্তু আমি callsite এ সময় একটি ত্রুটি পাবেন: Static method … requires that 'MyDecodable.Type' conform to 'Decodable'। আপনি কি একটি উত্তর কল দিতে আপনার উত্তর আপডেট করার আপত্তি করতে চান loadItem?
ব্যারি জোন্স

এটি সেই বিন্দুতে পরিণত হয় যেখানে আমাকে .Typeএবং .self(টাইপ এবং মেটাটাইপ) মধ্যে পার্থক্য শিখতে হয় ।
ব্যারি জোন্স


0

সুইফট 5

ঠিক একই অবস্থা নয়, তবে আমারও একই সমস্যা ছিল similar অবশেষে যা আমাকে সাহায্য করেছিল তা হ'ল:

func myFunction(_ myType: AnyClass)
{
    switch type
    {
        case is MyCustomClass.Type:
            //...
            break

        case is MyCustomClassTwo.Type:
            //...
            break

        default: break
    }
}

তারপরে আপনি এটিকে বলা ক্লাসের উদাহরণের মধ্যে কল করতে পারেন:

myFunction(type(of: self))

আশা করি এটি আমার একই পরিস্থিতিতে কাউকে সহায়তা করবে।

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