I'm relatively new to swift and searched around but could not find any satisfactory answer to my problem. I would like to have a Singleton class instance which can be initialized with some variables. E.g.
public class Singleton {
var car: String
var bus: String
init(car: String, bus: String) {
self.car = car
self.car = bus
}
func drive() {
print("I will drive")
}
}
public class SingletonConsumer {
// create an instance of Singleton Once
var driver: Singleton = Singleton(car: "honda", bus: "volvo")
driver.drive()
}
public class driverClassWorld : SingletonConsumer {
driver.drive()
}
how can i achieve it? I tried protocol but issue i am hitting is how to instantiate singleton class with parameters.
I don't get this problem?
First remove singleton from your brain for a moment. Because I think you have the wrong idea on what a singleton is.
Now lets rephrase your question to: "How to instantiate a class with parameter"
Its like this:
import Foundation
class Test {
let someText : String!
init(something:String){
someText = something
}
func test(){
print("TEST \(someText)")
}
}
let a = Test(something: "Me")
a.test()
Output:
TEST Optional("Me")
You just need to define a init with the parameters you want.
Now to properly instantiate a singleton (basically it just the class above but single instance). There are a lot of ways, the old Objective C approach is still valid.
But for swift this is the most common pattern. You need to define a Static Property.
Example:
import Foundation
class Test {
static let shared = Test(something: "REAL SINGLETON")
let someText : String!
init(something:String){
someText = something
}
func test(){
print("TEST \(someText)")
}
}
Test.shared.test()
Output:
TEST Optional("REAL SINGLETON")
Now reread the definition of a singleton:
a singleton class is a class that can have only one object (an
instance of the class) at a time
For other patterns in declaring a singleton:
https://cocoacasts.com/what-is-a-singleton-and-how-to-create-one-in-swift
Now, you might wonder: When does this singleton instance instantiated?
Answer: It is when it is first used/called.
Related
I am trying to use a class func to set a title for a book, however it's not working. Please see my code below:
import Foundation
class Book: NSObject {
var bookTitle: String = ""
var bookPage: String = ""
override init(){
print("Book object has been created")
}
class func setPageTitle(title: String)
{
bookTitle = title //I get the error here
}
}
I want to make it mandatory to set a pageTitle when a Book object is created.
Can someone please help me ?
The best way to set any required property/attribute is when you initialize it. So try coding your class this way:
class Book: NSObject {
var bookTitle: String = ""
var bookPage: String = ""
init(title:String) {
bookTitle = title
print("Book object has been created")
}
}
Several notes:
Your error is because you declare class in your setPageTitle function. That makes no sense.
There are better (and other) ways to set the bookTitle, including after initialization. But you specifically wanted to make sure you have a title when initializing, so there you go.
There are definitely better ways to maintain the bookTitle attribute. (Most languages teach you to hold a price variable to start with.) I'm mostly trying to give you a way to initialize it with the class.
You probably don't need (or have) any superclass call to make, but you also may not need to make your Book class a NSObject either.
Really basic question. I'm currently trying to code in a more Object Oriented way but there is something that I don't fully understand. I believe this applies to multiple programming languages not only Swift because I have seen this in some PHP code too.
I was under the impression that in order for you to access methods in a class you would need to create an instance but I'm not sure how this happens when you pass objects as parameters.
In the code below the moveDog(move:Animal) method gets an Animal object as a parameter, what I don't know understand is how can you access methods form the Animal object without instantiating the class first (print(move.run()))?
Does instantiation happens when declaring local parameters moveDog(move:Animal)? Can we say that it is the same as if we would do let move = Animal()?
class Animal{
func run(){
print("Running...")
}
}
class Dog{
func moveDog(move:Animal){
//how can the run method be called without
//having to instantiate Animal?
print(move.run())
}
}
let dog = Animal()
let buddy = Dog()
buddy.moveDog(dog)
The initialisation happens when you actually create it, e.g. let dog = Animal() or let buddy = Dog().
A quick note, you can make this code better by using the same run() function by using inheritance like so:
class Animal{
func run(){
print("Running...")
}
}
class Dog: Animal{
override func run() {
super.run()
}
}
let dog = Animal() //You don't need to instantiate this to use the Dog class
let buddy = Dog()
buddy.run()
In swift parameters are normally passed by reference (except structs) rather than being copied. So there's no initialisation for passing parameters.
I am writing method which takes a type which conforms to a protocol and instantiates an instance of this class. When I build it, the compiler crashes with a segfault. I appreciate that this points to a compiler bug 99% of the time, but I am interested to see if what I'm trying to do is logically correct or am I just throwing absolute nonsense at the compiler and I shouldn't be surprised to see it crash.
Here is my code
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
class ClassCreator {
class func createClass(classType: CreatableClass.Type) -> CreatableClass {
return classType()
}
}
ClassCreator.createClass(ExampleClass.self)
I also tried to rule out passing a Type as a method parameter as being the root of the problem and the following code also crashes the compiler:
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
let classType: CreatableClass.Type = CreatableClass.self
let instance = classType()
So - is this just a straightforward compiler bug and does what I am trying to do seem reasonable, or is there something in my implementation that is wrong?
Edit:
This can be achieved using generics as shown #Antonio below but unfortunately i believe that isn't useful for my application.
The actual non-dumbed down use-case for doing this is something like
protocol CreatableClass {}
protocol AnotherProtocol: class {}
class ClassCreator {
let dictionary: [String : CreatableClass]
func addHandlerForType(type: AnotherProtocol.Type, handler: CreatableClass.Type) {
let className: String = aMethodThatGetsClassNameAsAString(type)
dictionary[className] = handler()
}
required init() {}
}
I usually do that by defining a generic method. Try this:
class func createClass<T: CreatableClass>(classType: T.Type) -> CreatableClass {
return classType()
}
Update
A possible workaround is to pass a closure creating a class instance, rather than passing its type:
class ClassCreator {
class func createClass(instantiator: () -> CreatableClass) -> (CreatableClass, CreatableClass.Type) {
let instance = instantiator()
let classType = instance.dynamicType
return (instance, classType)
}
}
let ret = ClassCreator.createClass { ExampleClass() }
The advantage in this case is that you can store the closure in a dictionary for example, and create more instances on demand by just knowing the key (which is something in 1:1 relationship with the class name).
I used that method in a tiny dependency injection framework I developed months ago, which I realized it works only for #objc-compatible classes only though, making it not usable for my needs...
Building on previous question which got resolved, but it led to another problem. If protocol/class types are stored in a collection, retrieving and instantiating them back throws an error. a hypothetical example is below. The paradigm is based on "Program to Interface not an implementation" What does it mean to "program to an interface"?
instantiate from protocol.Type reference dynamically at runtime
public protocol ISpeakable {
init()
func speak()
}
class Cat : ISpeakable {
required init() {}
func speak() {
println("Meow");
}
}
class Dog : ISpeakable {
required init() {}
func speak() {
println("Woof");
}
}
//Test class is not aware of the specific implementations of ISpeakable at compile time
class Test {
func instantiateAndCallSpeak<T: ISpeakable>(Animal:T.Type) {
let animal = Animal()
animal.speak()
}
}
// Users of the Test class are aware of the specific implementations at compile/runtime
//works
let t = Test()
t.instantiateAndCallSpeak(Cat.self)
t.instantiateAndCallSpeak(Dog.self)
//doesn't work if types are retrieved from a collection
//Uncomment to show Error - IAnimal.Type is not convertible to T.Type
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for animal in animals {
//t.instantiateAndCallSpeak(animal) //throws error
}
for (index:Int, value:ISpeakable.Type) in enumerate(animals) {
//t.instantiateAndCallSpeak(value) //throws error
}
Edit - My current workaround to iterate through collection but of course it's limiting as the api has to know all sorts of implementations. The other limitation is subclasses of these types (for instance PersianCat, GermanShepherd) will not have their overridden functions called or I go to Objective-C for rescue (NSClassFromString etc.) or wait for SWIFT to support this feature.
Note (background): these types are pushed into array by users of the utility and for loop is executed on notification
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for Animal in animals {
if Animal is Cat.Type {
if let AnimalClass = Animal as? Cat.Type {
var instance = AnimalClass()
instance.speak()
}
} else if Animal is Dog.Type {
if let AnimalClass = Animal as? Dog.Type {
var instance = AnimalClass()
instance.speak()
}
}
}
Basically the answer is: correct, you can't do that. Swift needs to determine the concrete types of type parameters at compile time, not at runtime. This comes up in a lot of little corner cases. For instance, you can't construct a generic closure and store it in a variable without type-specifying it.
This can be a little clearer if we boil it down to a minimal test case
protocol Creatable { init() }
struct Object : Creatable { init() {} }
func instantiate<T: Creatable>(Thing: T.Type) -> T {
return Thing()
}
// works. object is of type "Object"
let object = instantiate(Object.self) // (1)
// 'Creatable.Type' is not convertible to 'T.Type'
let type: Creatable.Type = Object.self
let thing = instantiate(type) // (2)
At line 1, the compiler has a question: what type should T be in this instance of instantiate? And that's easy, it should be Object. That's a concrete type, so everything is fine.
At line 2, there's no concrete type that Swift can make T. All it has is Creatable, which is an abstract type (we know by code inspection the actual value of type, but Swift doesn't consider the value, just the type). It's ok to take and return protocols, but it's not ok to make them into type parameters. It's just not legal Swift today.
This is hinted at in the Swift Programming Language: Generic Parameters and Arguments:
When you declare a generic type, function, or initializer, you specify the type parameters that the generic type, function, or initializer can work with. These type parameters act as placeholders that are replaced by actual concrete type arguments when an instance of a generic type is created or a generic function or initializer is called. (emphasis mine)
You'll need to do whatever you're trying to do another way in Swift.
As a fun bonus, try explicitly asking for the impossible:
let thing = instantiate(Creatable.self)
And... swift crashes.
From your further comments, I think closures do exactly what you're looking for. You've made your protocol require trivial construction (init()), but that's an unnecessary restriction. You just need the caller to tell the function how to construct the object. That's easy with a closure, and there is no need for type parameterization at all this way. This isn't a work-around; I believe this is the better way to implement that pattern you're describing. Consider the following (some minor changes to make the example more Swift-like):
// Removed init(). There's no need for it to be trivially creatable.
// Cocoa protocols that indicate a method generally end in "ing"
// (NSCopying, NSCoding, NSLocking). They do not include "I"
public protocol Speaking {
func speak()
}
// Converted these to structs since that's all that's required for
// this example, but it works as well for classes.
struct Cat : Speaking {
func speak() {
println("Meow");
}
}
struct Dog : Speaking {
func speak() {
println("Woof");
}
}
// Demonstrating a more complex object that is easy with closures,
// but hard with your original protocol
struct Person: Speaking {
let name: String
func speak() {
println("My name is \(name)")
}
}
// Removed Test class. There was no need for it in the example,
// but it works fine if you add it.
// You pass a closure that returns a Speaking. We don't care *how* it does
// that. It doesn't have to be by construction. It could return an existing one.
func instantiateAndCallSpeak(builder: () -> Speaking) {
let animal = builder()
animal.speak()
}
// Can call with an immediate form.
// Note that Cat and Dog are not created here. They are not created until builder()
// is called above. #autoclosure would avoid the braces, but I typically avoid it.
instantiateAndCallSpeak { Cat() }
instantiateAndCallSpeak { Dog() }
// Can put them in an array, though we do have to specify the type here. You could
// create a "typealias SpeakingBuilder = () -> Speaking" if that came up a lot.
// Again note that no Speaking objects are created here. These are closures that
// will generate objects when applied.
// Notice how easy it is to pass parameters here? These don't all have to have the
// same initializers.
let animalBuilders: [() -> Speaking] = [{ Cat() } , { Dog() }, { Person(name: "Rob") }]
for animal in animalBuilders {
instantiateAndCallSpeak(animal)
}
I have following code snippets:
protocol UpdateUIFromNativeListenerItf {
func triggerUI()
}
class WmBuildGroupsTask{
var mUfn:UpdateUIFromNativeListenerItf?
init(){/* ... */}
// ...
class func triggerRegister( ufn: UpdateUIFromNativeListenerItf ) {
mUfn = ufn // WmBuildGroupsTask.Type does not have `mUfn`
}
}
Form other class I call:
var ufn:UpdateUIFromNativeListenerItf = self
WmBuildGroupsTask.triggerRegister(ufn)
How can I pass delegate to static method?
Do I need create singleton for class WmBuildGroupsTask?
I tried also to write class var mUfn:UpdateUIFromNativeListenerItf?
But get: Class var not yet supported
Thanks,
Static stored properties are not supported in swift classes (yet), but they are in structs. So you can create an inline private struct and define your static properties there:
class WmBuildGroupsTask{
private struct Static {
static var mUfn:UpdateUIFromNativeListenerItf?
}
init(){/* ... */}
// ...
class func triggerRegister( ufn: UpdateUIFromNativeListenerItf ) {
Static.mUfn = ufn // WmBuildGroupsTask.Type does not have `mUfn`
}
}
The downside is that you have to access the static property prefixing it with the struct name - but I guess that's an acceptable tradeoff.
There is also another obvious way to solve the problem: turn the class into a struct, so obvious that it's enough to just mention it. Just a consideration: structs and classes are not interchangeable, they have their own pros and cons.
You are trying to access a member variable in a static context. mUfn is stored for an instance of your class, not for the class itself.