কীভাবে সুইফট ল্যাঙ্গুয়েজে প্রতিবিম্ব অর্জন করবেন ?
আমি কীভাবে কোনও ক্লাস ইনস্ট্যান্ট করতে পারি
[[NSClassFromString(@"Foo") alloc] init];
কীভাবে সুইফট ল্যাঙ্গুয়েজে প্রতিবিম্ব অর্জন করবেন ?
আমি কীভাবে কোনও ক্লাস ইনস্ট্যান্ট করতে পারি
[[NSClassFromString(@"Foo") alloc] init];
উত্তর:
এখানে কম হ্যাকির সমাধান: https://stackoverflow.com/a/32265287/308315
নোট করুন যে সুইফ্ট ক্লাসগুলি এখন "মাইভিউকন্ট্রোলার" এর পরিবর্তে নামকরণ করা হয়েছে এটি "অ্যাপনাম.মাইভিউকন্ট্রোলার" হবে
এক্সকোডি 6-বিটা 6/7 থেকে অবহেলিত
এক্সকোড 6-বিটা 3 ব্যবহার করে সমাধানটি বিকশিত হয়েছিল
এডউইন ভারমিরের উত্তরের জন্য ধন্যবাদ আমি এটি করে ওফজে-সি ক্লাসে সুইফ্ট ক্লাস ইনস্ট্যান্ট করার জন্য কিছু তৈরি করতে সক্ষম হয়েছি:
// swift file
// extend the NSObject class
extension NSObject {
// create a static method to get a swift class for a string name
class func swiftClassFromString(className: String) -> AnyClass! {
// get the project name
if var appName: String? = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as String? {
// generate the full name of your class (take a look into your "YourProject-swift.h" file)
let classStringName = "_TtC\(appName!.utf16count)\(appName)\(countElements(className))\(className)"
// return the class!
return NSClassFromString(classStringName)
}
return nil;
}
}
// obj-c file
#import "YourProject-Swift.h"
- (void)aMethod {
Class class = NSClassFromString(key);
if (!class)
class = [NSObject swiftClassFromString:(key)];
// do something with the class
}
সম্পাদনা
আপনি এটি খাঁটি আপত্তি-সিতেও করতে পারেন:
- (Class)swiftClassFromString:(NSString *)className {
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSString *classStringName = [NSString stringWithFormat:@"_TtC%d%@%d%@", appName.length, appName, className.length, className];
return NSClassFromString(classStringName);
}
আমি আশা করি এটি কারও সাহায্য করবে!
আপনাকে অবশ্যই @objc(SwiftClassName)আপনার সুইফ্ট ক্লাসের উপরে রাখতে হবে ।
পছন্দ:
@objc(SubClass)
class SubClass: SuperClass {...}
NSClassFromString()ফাংশনটির জন্য @objcঅ্যাট্রিবিউশন দ্বারা নির্দিষ্ট নাম প্রয়োজন ।
@objc(SubClass)কাজ করে @objc class SubClass?
@objc class SubClassসিটির জন্য দৃশ্যমান হবে the ফর্মটিতে নামটি সাবক্লাস নামের মতোই বোঝানো হয়েছে। এবং @objc(SubClass) class SubClassফর্ম এটি সরাসরি নির্দিষ্ট করা হয়। আমার ধারণা, সংকলকটি কোনও কারণে প্রথম ফর্মটিতে নিজেই এটি বের করতে পারে না।
এইভাবে আমি ক্লাস নাম অনুসারে ইউআইভিউউকন্ট্রোলার উদ্ভব করেছি
var className = "YourAppName.TestViewController"
let aClass = NSClassFromString(className) as! UIViewController.Type
let viewController = aClass()
আরও তথ্য এখানে
আইওএস 9 এ
var className = "YourAppName.TestViewController"
let aClass = NSClassFromString(className) as! UIViewController.Type
let viewController = aClass.init()
আপডেট: বিটা 6 দিয়ে শুরু করে এনএসএসটিংফ্রমক্লাস আপনার বান্ডিলের নাম এবং ডট দ্বারা পৃথক শ্রেণীর নাম ফিরিয়ে দেবে। সুতরাং এটি MyApp.MyClass এর মতো কিছু হবে
সুইফ্ট ক্লাসগুলির একটি অন্তর্নির্মিত অভ্যন্তরীণ নাম থাকবে যা নিম্নলিখিত অংশগুলির তৈরি:
সুতরাং আপনার শ্রেণীর নামটি এমন কিছু হবে যা _TtC5MyApp7MyClass এর মতো
এক্সিকিউট করে আপনি স্ট্রিং হিসাবে এই নামটি পেতে পারেন:
var classString = NSStringFromClass(self.dynamicType)
সুইফ্ট 3-এ আপডেট করুন এটি এতে পরিবর্তিত হয়েছে:
var classString = NSStringFromClass(type(of: self))
সেই স্ট্রিংটি ব্যবহার করে, আপনি কার্যকর করে আপনার সুইফ্ট শ্রেণির একটি উদাহরণ তৈরি করতে পারেন:
var anyobjectype : AnyObject.Type = NSClassFromString(classString)
var nsobjectype : NSObject.Type = anyobjectype as NSObject.Type
var rec: AnyObject = nsobjectype()
এটা প্রায় একই
func NSClassFromString(_ aClassName: String!) -> AnyClass!
এই দস্তাবেজটি পরীক্ষা করুন:
NSClassক্লাস নিয়ে কাজ করে , সুইফ্ট ক্লাসগুলির সাথে নয়। NSClassFromString("String")ফিরে আসে nil, কিন্তু NSClassFromString("NSString")না।
var myVar:NSClassFromString("myClassName")
Stringকোনও শ্রেণি নয়; এটি একটি কাঠামো
NSClassFromStringরিটার্ন দেয় nil।
আমি কোনও বস্তুকে গতিশীলভাবে ইনস্ট্যান্ট করতে সক্ষম হয়েছি
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!")
}
আমি AnyClassকোনও String(ওবজ-সি ব্যবহার না করে) তৈরির উপায় খুঁজে পাইনি । আমি মনে করি তারা আপনাকে এটি করতে চায় না কারণ এটি মূলত টাইপ সিস্টেমটি ভেঙে দেয়।
সুইফট 2-এর জন্য, আমি এটি আরও দ্রুত করার জন্য খুব সাধারণ এক্সটেনশন তৈরি করেছি https://github.com/damienromito/NSObject-FromClassName
extension NSObject {
class func fromClassName(className : String) -> NSObject {
let className = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String + "." + className
let aClass = NSClassFromString(className) as! UIViewController.Type
return aClass.init()
}
}
আমার ক্ষেত্রে, আমি যে ভিউ কন্ট্রোলার চাই তা লোড করার জন্য এটি করি:
override func viewDidLoad() {
super.viewDidLoad()
let controllers = ["SettingsViewController", "ProfileViewController", "PlayerViewController"]
self.presentController(controllers.firstObject as! String)
}
func presentController(controllerName : String){
let nav = UINavigationController(rootViewController: NSObject.fromClassName(controllerName) as! UIViewController )
nav.navigationBar.translucent = false
self.navigationController?.presentViewController(nav, animated: true, completion: nil)
}
এটি আপনাকে যে ক্লাসটি ইনস্ট্যান্ট করতে চাইবে তার নাম পাবে। তারপরে আপনি এডউইনস উত্তরটি ব্যবহার করতে পারেন আপনার শ্রেণীর কোনও নতুন অবজেক্ট ইনস্ট্যান্ট ।
বিটা 6 _stdlib_getTypeNameএর মত একটি ভেরিয়েবলের ম্যাংলেড টাইপের নাম পান। এটি খালি খেলার মাঠে আটকান:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
আউটপুটটি হ'ল:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
ইভান সুইকের ব্লগ এন্ট্রি এই স্ট্রিংগুলি বোঝাতে সহায়তা করে: http://www.eswick.com/2014/06/inside-swift/
উদাহরণস্বরূপ _TtSiসুইফট এর অভ্যন্তরীণ Intপ্রকার বোঝায় ।
let vcName = "HomeTableViewController"
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
// Convert string to class
let anyobjecType: AnyObject.Type = NSClassFromString(ns + "." + vcName)!
if anyobjecType is UIViewController.Type {
// vc is instance
let vc = (anyobjecType as! UIViewController.Type).init()
print(vc)
}
ক্লাস থেকে স্ট্রিং
let classString = NSStringFromClass(TestViewController.self)
বা
let classString = NSStringFromClass(TestViewController.classForCoder())
স্ট্রিং থেকে একটি ইউআইভিউ কনট্রোলার ক্লাস শুরু করুন:
let vcClass = NSClassFromString(classString) as! UIViewController.Type
let viewController = vcClass.init()
আমি এই বিভাগটি সুইফট 3 এর জন্য ব্যবহার করছি:
//
// String+AnyClass.swift
// Adminer
//
// Created by Ondrej Rafaj on 14/07/2017.
// Copyright © 2017 manGoweb UK Ltd. All rights reserved.
//
import Foundation
extension String {
func convertToClass<T>() -> T.Type? {
return StringClassConverter<T>.convert(string: self)
}
}
class StringClassConverter<T> {
static func convert(string className: String) -> T.Type? {
guard let nameSpace = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String else {
return nil
}
guard let aClass: T.Type = NSClassFromString("\(nameSpace).\(className)") as? T.Type else {
return nil
}
return aClass
}
}
ব্যবহারটি হবে:
func getViewController(fromString: String) -> UIViewController? {
guard let viewController: UIViewController.Type = "MyViewController".converToClass() else {
return nil
}
return viewController.init()
}
আমি মনে করি আমি ঠিক বলেছি যে আপনি পারবেন না, কমপক্ষে বর্তমান বিটা (2) এর সাথে নয়। আশা করি এটি এমন কিছু যা ভবিষ্যতের সংস্করণগুলিতে পরিবর্তিত হবে।
আপনি NSClassFromStringটাইপের একটি ভেরিয়েবল পেতে ব্যবহার করতে পারেন AnyClassতবে সুইফের এটি ইনস্ট্যান্ট করার কোনও উপায় নেই বলে মনে হয়। আপনি উদ্দেশ্য সি এর জন্য একটি সেতু ব্যবহার করতে পারেন এবং এটি সেখানে করতে পারেন - বা এটি আপনার ক্ষেত্রে কাজ করে - একটি স্যুইচ স্টেটমেন্ট ব্যবহার করে পিছিয়ে যান ।
স্পষ্টতই, ক্লাসের নামটি কেবল রানটাইমের সময় জানা গেলে সুইফটে কোনও বস্তু ইনস্ট্যান্ট করা (আর) সম্ভব নয়। এনএসবজেক্টের সাবক্লাসের জন্য একটি অবজেক্টিভ-সি র্যাপার সম্ভব।
কমপক্ষে আপনি একই শ্রেণীর কোনও অবজেক্টকে অবজেক্টি-সি মোড়ক ছাড়াই রানটাইমে প্রদত্ত অন্য কোনও অবজেক্টের মতো ইনস্ট্যান্ট করতে পারেন (xCode সংস্করণ 6.2 - 6C107a ব্যবহার করে):
class Test : NSObject {}
var test1 = Test()
var test2 = test1.dynamicType.alloc()
সুইফট ২.০ (এক্সকোড 7 এর বিটা ২ তে পরীক্ষিত) এ এটির মতো কাজ করে:
protocol Init {
init()
}
var type = NSClassFromString(className) as? Init.Type
let obj = type!.init()
নিশ্চিতভাবে যে ধরণের আগমন ঘটে NSClassFromStringতা এই init প্রোটোকলটি প্রয়োগ করতে হবে।
আমি আশা করি এটি পরিষ্কার হয়ে গেছে, className ক্লাসের ওবজ-সি রানটাইম নাম সম্বলিত একটি স্ট্রিং যা ডিফল্টরূপে কেবল "ফু" নয়, তবে এই আলোচনাটি আপনার প্রশ্নের প্রধান বিষয় নয় আইএমএইচও।
আপনার এই প্রোটোকলটি প্রয়োজন কারণ ডিফল্ট হোন সমস্ত সুইফ্ট ক্লাস কোনও initপদ্ধতি প্রয়োগ করে না ।
দেখে মনে হচ্ছে সঠিক জ্বলনটি হ'ল ...
func newForName<T:NSObject>(p:String) -> T? {
var result:T? = nil
if let k:AnyClass = NSClassFromString(p) {
result = (k as! T).dynamicType.init()
}
return result
}
... যেখানে "পি" "প্যাকেজড" - এর একটি স্বতন্ত্র সমস্যা for
তবে অ্যানিক্লাস থেকে টি তে সমালোচনামূলক castালাই বর্তমানে একটি সংকলক ক্র্যাশ ঘটায়, সুতরাং এর মধ্যে একজনকে অবশ্যই K এর আরম্ভকরণটি পৃথক বন্ধে আবদ্ধ করতে হবে, যা জরিমানা সংকলন করে।
আমি বিভিন্ন লক্ষ্যবস্তু ব্যবহার করি এবং এই ক্ষেত্রে সুইফ্ট ক্লাসটি পাওয়া যায় না। আপনার CFBundleExecutable এর সাথে CFBundleName প্রতিস্থাপন করা উচিত। আমি সতর্কতাগুলিও স্থির করেছিলাম:
- (Class)swiftClassFromString:(NSString *)className {
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"];
NSString *classStringName = [NSString stringWithFormat:@"_TtC%lu%@%lu%@", (unsigned long)appName.length, appName, (unsigned long)className.length, className];
return NSClassFromString(classStringName);
}
সমাধান কি এর মতো সহজ নয়?
// Given the app/framework/module named 'MyApp'
let className = String(reflecting: MyClass.self)
// className = "MyApp.MyClass"
এছাড়াও সুইফট 2.0 (সম্ভবত আগে?) এ সরাসরি আপনার সাথে টাইপ অ্যাক্সেস করতে পারেন dynamicTypeসম্পত্তি
অর্থাত্
class User {
required init() { // class must have an explicit required init()
}
var name: String = ""
}
let aUser = User()
aUser.name = "Tom"
print(aUser)
let bUser = aUser.dynamicType.init()
print(bUser)
আউটপুট
aUser: User = {
name = "Tom"
}
bUser: User = {
name = ""
}
আমার ব্যবহারের ক্ষেত্রে কাজ করে
আমি এভাবে বাস্তবায়ন করেছি,
if let ImplementationClass: NSObject.Type = NSClassFromString(className) as? NSObject.Type{
ImplementationClass.init()
}
সুইফট 5 , ব্যবহার করা সহজ, @ ওন্দ্রেজ রাফাজের জন্য ধন্যবাদ
সোর্স কোড:
extension String {
fileprivate
func convertToClass<T>() -> T.Type? {
return StringClassConverter<T>.convert(string: self)
}
var controller: UIViewController?{
guard let viewController: UIViewController.Type = convertToClass() else {
return nil
}
return viewController.init()
}
}
class StringClassConverter<T> {
fileprivate
static func convert(string className: String) -> T.Type? {
guard let nameSpace = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String, let aClass = NSClassFromString("\(nameSpace).\(className)") as? T.Type else {
return nil
}
return aClass
}
}
এভাবে কল করুন:
guard let ctrl = "ViewCtrl".controller else {
return
}
// ctrl do sth
একটি পৃষ্ঠার জাম্প উদাহরণ এখানে দেখানো হয়েছে, আশা আপনাকে সাহায্য করতে পারে!
let vc:UIViewController = (NSClassFromString("SwiftAutoCellHeight."+type) as! UIViewController.Type).init()
self.navigationController?.pushViewController(vc, animated: true)
// Click the Table response
tableView.deselectRow(at: indexPath, animated: true)
let sectionModel = models[(indexPath as NSIndexPath).section]
var className = sectionModel.rowsTargetControlerNames[(indexPath as NSIndexPath).row]
className = "GTMRefreshDemo.\(className)"
if let cls = NSClassFromString(className) as? UIViewController.Type {
let dvc = cls.init()
self.navigationController?.pushViewController(dvc, animated: true)
}
সুইফট 3 +
extension String {
var `class`: AnyClass? {
guard
let dict = Bundle.main.infoDictionary,
var appName = dict["CFBundleName"] as? String
else { return nil }
appName.replacingOccurrences(of: " ", with: "_")
let className = appName + "." + self
return NSClassFromString(className)
}
}
এখানে একটি ভাল উদাহরণ:
class EPRocks {
@require init() { }
}
class EPAwesome : EPRocks {
func awesome() -> String { return "Yes"; }
}
var epawesome = EPAwesome.self();
print(epawesome.awesome);