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.
Related
A class variable that contains the class itself, for example, the main property of the class DispatchQueue
Question 1
What kind of design pattern it is? Is this related to Singleton?
Question 2
How does the object initialized when referring this property?
Yes, it is the singleton pattern. It is all over swift like UserDefaults.standard, NotificationCenter.default, FileManager.default, ... For instance, URLSession.shared is defined in the apple docs as:
The shared singleton session object.
The singleton pattern makes sure that only one instance of the class is created. The class lazily creates its sole instance the first time it is requested and thereafter ensures that no other instance can be created.
Here is some sample code:
class MyClass {
static let shared = MyClass()
//Make the initializer private
private init(){}
//Here is a sample method
func doSomething() {
print("Doing something")
}
}
Making the initializer prevents the possibility of creating many instances, and thus the following line would yield an error:
let instance = MyClass() //MyClass initializer is inaccessible due to private protection level
To access the singleton use MyClass.shared:
let instance = MyClass.shared
instance.doSomething() //Prints: Doing something
For more details on the singleton pattern in Swift, you may look here and here.
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.
To create a singleton class, I wrote something like this:
class SingletonEx{
var name = ""
private init(){}
static let sharedInstance = SingletonEx()
func instanceMethod(){
}
static func classMethod(){
}
}
Some tutorials say final is necessary while others just ignore final keyword. After I tried subclassing SingletonEx, I got the following results.
It seems I can't write an initializer for subclass, which means I can't use an override instance method in a subclass.
As far as I know, singleton definition is all about single instantiation and accessing instance methods through the only instance. So I don't think it is necessary to use final in the singleton definition. But both my teachers and some online tutorials say it is necessary.
I got confused, since you can't create a subclass instance anyway, even you override the instance methods, you can't use it or access it, what's the point to say final is necessary for a singleton class?
If I am wrong, please point out.
Super Class
First of all you need to know the properties and methods that are marked with private are just known to the Super class and Sub classes won't access them!
A class can inherit methods, properties, and other characteristics from another class. When one class inherits from another, the inheriting class is known as a subclass, and the class it inherits from is known as its superclass. Inheritance is a fundamental behavior that differentiates classes from other types in Swift.
Classes in Swift can call and access methods, properties, and subscripts belonging to their superclass and can provide their own overriding versions of those methods, properties, and subscripts to refine or modify their behavior. Swift helps to ensure your overrides are correct by checking that the override definition has a matching superclass definition.
In your case in SingletonEx class you market init with private which means that you can create object just in the body of the class! that means no one, no where, can't create an object of SingletonEx!
If you want to a method end up in Super Class and you don't want to Sub classes overide that method you need to mark that method with final which means it's not private but its available only from Super class!
Sub Class
When class Y Inheritance from SingletonEx which means that cant create an object outside of the class ! because Super class initializer is unavailable during init() method from class Y ! While you need to call the super.init() if you want to initialize an object from Y class !
if you remove private from private init() {} from SingletonEx class you be able to create object from SingletonEx class and also from Y class !
your code should looks like this :
Swift 4 :
class SingletonEx{
var name = ""
init(){}
static let sharedInstance = SingletonEx()
func instanceMethod(){
}
static func classMethod(){
}
}
class Y : SingletonEx {
private var yName = "Y name is : "
init(name:String) {
super.init()
self.name = self.yName + name
}
}
Usage :
override func viewDidLoad() {
super.viewDidLoad()
let yObject = Y.init(name: "badGirl :D ")
print(yObject)
// --> Output : Y name is : badGirl :D
}
I already know that we can get the list of attributes of a object using reflection in Swift, but all the examples that I found and have implemented so far uses a instantiate object. Something like that:
func attributeList() -> [String] {
var attributeList = [String]()
let serializableMirror = Mirror(reflecting: self) //using instantiate object
for childMirror in serializableMirror.children {
if let label = childMirror.label {
attributeList.append(label)
}
}
return attributeList
}
My question is, there is any way to get the attributes of a class without any reference to it? Some kind of static method where I pass my desired class type and get the attributes list of it.
In all implementations of reflection that I've worked with you need an object for the reflection to work on.
Whether it's one you provide or one the system creates for you, you have to have a concrete object.
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)
}