I have a static method in Swift
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled:CustomBool)
{
// Print class name (BaseAsyncTask) here
}
}
And I want to know how to get the class name inside that method. I tried
self.dynamicType
but that gives error (I suppose because of the self inside a class function)
There are different methods to do that, if your method inherits from NSObject you can expose it to objective-c and do something like that.
#objc(BaseAsyncTask)
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled:CustomBool)
{
println("Class \(NSStringFromClass(self))")
}
}
For pure SWIFT introspection check here about MirrorType
I've found also this extension credits to ImpactZero
public extension NSObject{
public class var nameOfClass: String{
return NSStringFromClass(self).components(separatedBy: ".").last!
}
public var nameOfClass: String{
return NSStringFromClass(type(of: self)).components(separatedBy: ".").last!
}
}
[Xcode 8]
Alex suggested me that in the Xcode 8 version this code shows a warning. To avoid that we should prefix the method like that:
#nonobjc class var className: String{
return NSStringFromClass(self).components(separatedBy: ".").last!
}
You can use string interpolation to print self:
let className = "\(self)"
Sample code:
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled: CustomBool)
{
let className = "\(self)"
print(className)
}
}
class AnotherAsyncTask : BaseAsyncTask {
}
BaseAsyncTask.execute([:], cancelled: true) // prints "BaseAsyncTask"
AnotherAsyncTask.execute([:], cancelled: true) // prints "AnotherAsyncTask"
Another way to do this, when you don't have an instance of the class is this.
Swift 4
print(String(describing:BaseAsyncTask.self))
Swift 2
print(String(BaseAsyncTask))
Inspired here.
Get class name of object as string in Swift
Related
I'm trying to create a simple framework that has a function that returns "hello name" name being a passed argument. Below is the framework and code trying to call it.
Framework:
public class Greeter {
public init () {}
public static func greet(name: String) -> String {
return "Hello /(name)."
}
}
Code:
import Greeter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let greetingString: String = Greeter.greet("Bob")
print(greetingString)
}
}
When I try typing out "greet("Bob")", what autocompletes is "(name: String) -> String greet(self: Greeter)". And when I manually type "greet("Bob")", I get the error: Instance member 'greet' cannot be used on type 'Greeter'; did you mean to use a value of this type instead?
You need to create an instance of Greeter class first and then call it's method.
let greeter = Greeter()
let greetingString: String = greeter.greet(name: "Bob")
print(greetingString)
Update: You don't need : String it's redundant here. So you can modify that line to:
let greetingString = greeter.greet(name: "Bob")
I hope to get a specific instance when I use my static method. For example:
class Food: NSObject {
var name: String
class func initFruit() -> Food? {
let fruitName = NSStringFromClass(self).components(separatedBy: ".").last! as String
if "Apple" == fruitName {
return Apple(name: fruitName)
} else if "Orange" == fruitName {
return Orange(name: fruitName)
}
return nil
}
init(name: String) {
self.name = name
}
}
class Apple: Food {
}
class Orange: Food {
}
When I create an Apple instance with the method:
let apple = Apple.initFruit() as? Apple
How can I get the specific instance apple rather than use as? Apple?. I wonder how to modify the method:
static func initFruit() -> Food?
There are a couple of problems with your design, let me try and enumerate them:
base classes should not be aware of their subclasses, it's bad practice and it's not scalable, as adding a new subclass would require maintaining the base class method
the static method is not needed at all, at least in the shape it's written in the question, you could simply directly call the initializers for the subclasses
Leaving all those aside, you can use Self as return type for the static method, this will allow dynamic results.
class Food: NSObject {
var name: String
class func initFruit() -> Self {
let fruitName = NSStringFromClass(self).components(separatedBy: ".").last! as String
return self.init(name: fruitName)
}
required init(name: String) {
self.name = name
}
}
class Apple: Food {
}
class Orange: Food {
}
let apple = Apple.initFruit() // is an Apple, no cast needed
i think it's not good idea because Food is parent class and Apple inherits Food. Apple may know it's parent class cause is extends Food but Food does not.
So, if you want to create instance by some string or some variable. I would like to recommend you to adopt "Factory pattern"
reference here:
https://medium.com/swift-programming/design-patterns-creational-patterns-factory-pattern-in-swift-d049af54235b
Inspired by the question Generics in Swift - "Generic parameter 'T' could not be inferred I find another way to resolve this question. I add a method to infer the specific type.
func ascertainFruitType<T>() -> T {
return self as! T // as! is dangerous
}
Then the method initFruit is changed on below:
class func initFruit() -> Self {
let fruitName = NSStringFromClass(self).components(separatedBy: ".").last! as String
if "Apple" == fruitName {
return Apple(name: fruitName).ascertainFruitType()
} else {
return Orange(name: fruitName).ascertainFruitType()
}
}
I started learning Swift today and in my first test app I am getting this error:
TestClass is not convertible to AnotherClass
The following is the TestClass:
class TestClass : NSObject {
var parameter1 : String = ""
var parameter2 : String = ""
override init() {
super.init()
}
func createJob(parameter1: String, parameter2: String) -> TestClass {
self.parameter1 = parameter1
self.parameter2 = parameter2
return self;
}
}
And this is the AnotherClass:
class AnotherClass: NSObject {
private struct internalConstants {
static let test1 = "testData"
static let test2 = "testData2"
}
var current : String
override init() {
self.current = internalConstants.test1
super.init()
}
func executeTask(testClass : TestClass) {
if testClass.parameter1 == "abc" {
return;
}
}
}
And this is the ViewController where I am getting the compiler error:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let obj = TestClass()
AnotherClass.executeTask(obj)
}
}
AnotherClass.executeTask line is giving the compiler error.
The obj variable sent as a parameter on this line is highlighted by Xcode with the error
"TestClass is not convertible to AnotherClass".
In C# or Objective C it is allowed to pass custom objects as a parameter to another methods. How can I do it in Swift?
Let's correct first the TestClass. This is how you should init a class like that:
class TestClass : NSObject {
....
init(parameter1: String, parameter2: String) {
....
}
}
Much simpler. Now, going back to your problem,
"TestClass is not convertible to AnotherClass".
Take a look at it again. The line you've mentioned in your question. You are trying to do this:
let obj = TestClass()
AnotherClass.executeTask(obj)
This line, AnotherClass.executeTask(obj), is giving you an error because indeed executeTask() is an instance method. You could do three ways for that.
add static keyword to the func executeTask... So it becomes like this: static func executeTask(testClass : TestClass) {
Instead of static keyword, you could add class. It becomes like so: class func executeTask(....
OR, better if you just instantiate the AnotherClass. Make a new object of AnotherClass. How to instantiate? You tell me. But here:
let anotherClass = AnotherClass()
Either implement executeTask as a class function
class func executeTask(testClass : TestClass) {
if testClass.parameter1 == "abc" {
return;
}
}
or instantiate AnotherClass in vieweDidLoad
let obj = TestClass()
let another = AnotherClass()
another.executeTask(testClass: obj)
Note the slightly different call to executeTask with the argument name.
And there is really no reason for you to subclass NSObject as I see it.
I think it's best to keep is simple. Create an instance of AnotherClass inside of ViewController.
class ViewController: UIViewController {
// Create an instance of AnotherClass which lives with ViewController.
var anotherClass = AnotherClass()
override func viewDidLoad() {
super.viewDidLoad()
let obj = TestClass()
// Use the instance of AnotherClass to call the method.
anotherClass.executeTask(testClass: obj)
}
}
If I have the following code:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
print(object.objectTypeString)
}
}
where Object conforms to ObjectType, you would expect that you can access objectTypeString on any ObjectInstance. But the compiler says that Type T has no member objectTypeString when that member is accessed on some generic type that inherits from Object, as shown in the code above. When the function is non-generic and just passes in an Object parameter, there's no issue. So why does have the parameter be generic make it so I can't access a member of the protocol that the conforming class should have access to?
I came across this question here but I'm not interested in workarounds, I'd just like to understand what it is about the generic system that makes my example not work. (Simple workaround is to do <T: ObjectType>)
Maybe I'm wrong or i didn't understand your question completely, but i think you might be missing initiating "object".
your willing code maybe the code below:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
let object = Object()
print(object.objectTypeString)
}
}
but the thing is, even if we dont initiate the object, the auto complete brings the objectTypeString up! that's what i don't understand, and as you said maybe its where the bug happens!
hope it helps <3
How to access to static protocol method within a instance
I have a list of Contact, the contact can be a FamilyContact that inherit from Contact and the GroupStatus protocol
I want to call the static method from GroupStatus but in vain...
Here is my code
protocol GroupStatus {
static func isPrivate() -> Bool // static method that indicates the status
}
protocol IsBusy {
func wizzIt()
}
class AdresseBook {
private var contacts = [Contact]()
func addOne(c: Contact) {
contacts.append(c)
}
func listNonPrivated() -> [Contact]? {
var nonPrivateContact = [Contact]()
for contact in contacts {
// here is I should call the static method provided by the protocol
if self is GroupStatus {
let isPrivate = contact.dynamicType.isPrivate()
if !isPrivate {
nonPrivateContact.append(contact)
}
}
nonPrivateContact.append(contact)
}
return nonPrivateContact
}
}
class Contact : Printable {
var name: String
init(name: String) {
self.name = name
}
func wizz() -> Bool {
if let obj = self as? IsBusy {
obj.wizzIt()
return true
}
return false
}
var description: String {
return self.name
}
}
class FamilyContact: Contact, GroupStatus {
static func isPrivate() -> Bool {
return true
}
}
I can't compile Contact.Type does not have a member named 'isPrivate'
How can I call it ? It works if I delete the static keyword, but I think is more logical to define it static.
If I replace
let isPrivate = contact.dynamicType.isPrivate()
by
let isPrivate = FamilyContact.isPrivate()
It works, but I can have more than 1 subclasses
If I remove the static keywork I can do it by this way :
if let c = contact as? GroupStatus {
if !c.isPrivate() {
nonPrivateContact.append(contact)
}
}
But I want to keep the static keyword
This looks like a bug or a non-supported feature. I would expect that
the following works:
if let gsType = contact.dynamicType as? GroupStatus.Type {
if gsType.isPrivate() {
// ...
}
}
However, it does not compile:
error: accessing members of protocol type value 'GroupStatus.Type' is unimplemented
It does compile with FamilyContact.Type instead of GroupStatus.Type. A similar problem is reported here:
Swift 1.1 and 1.2: accessing members of protocol type value XXX.Type' is unimplemented
Making isPrivate() an instance method instead of a class method is
the only workaround that I currently can think of, maybe someone comes
with a better solution ...
Update for Swift 2 / Xcode 7: As #Tankista noted below, this has
been fixed. The above code compiles and works as expected in Xcode 7 beta 3.
type(of: contact).isPrivate()
This should work in recent Swift.