Swift cannot assign to self in a class init method - swift

I have a class called Letter
class Letter
{
init() {}
}
And I have an extension for this class:
extension Letter
{
convenience init(file_path:String) {
self = Letter.loadFromFile(file_path)
}
class func loadFromFile(file_path:String)->Letter {...}
}
I need to create and init with path to file and when i call Letter(file_path) I need a new object that returned by a func loadFromFile. How to assign in an init method or to return a new object?
It gives the error:
Cannot assign to value: 'self' is immutable

Class functions that return instances of that class seems to be an anti-pattern in Swift. You'll notice that the "with" Objective-C class methods like [NSString stringWithString:#"some other string"] made the transition as "with"-less convenience initializers: NSString(string: "some other string").
Furthermore, you'll need to delegate to a designated initializer from within a convenience initializer.
Also, since you're 1) defining the original class and 2) don't need the convenience initializer scoped differently than the designated initializer, I don't see any reason to place it in an extension.
Putting those together:
class Letter {
init() { … }
convenience init(filePath: String) {
self.init()
loadFromFile(filePath)
}
func loadFromFile(filePath: String) { … }
}
let letter1 = Letter()
letter1.loadFromFile("path1")
let letter2 = Letter(filePath: "path2")
In summary, the analogy for assigning to self in Swift is calling an initializer.
Let me know if this works for you!

Convenience initializer must delegate up to designated initializer
It says that convenience init(file_path:String) should call other initialiser
convenience init(file_path:String) {
self.init()
//here can set other properties
}
Convenience initialiser usually provide some default parameters
Convenience initialiser are designed to make creation of class instance less complicated. It means that you don't need to pass all arguments to constructor. In your example the class should look like this
Designated initializer takess all possible arguments.
Convenience provide default value
Code example
// Create instance of a Letter
Letter()
Letter(file_path: "path.txt")
Letter(file_path: "path.txt", option: 0, other: 0)
//Class Implementation
class Letter
{
init(file_path: String , option: Int, other: Int) {
// Instansiate class
}
}
extension Letter {
convenience init() {
self.init(file_path:"a")
}
convenience init(file_path:String) {
self.init(file_path: file_path , option: 0, other: 0)
}
class func loadFromFile(file_path:String) -> Letter {
return Letter()
}
}
Now you can create instance of Letter this way -

You can't assign to self. What about something like this:
class Letter {
}
extension Letter {
convenience init(filePath: String) {
self.init()
// code to load a Letter from a file goes here.
}
class func loadFromFile(filePath: String) -> Letter {
return Letter(filePath: filePath)
}
}

Related

How to prevent subclasses from inheriting super class's static method in Swift?

In the case of the following code, it is possible to call both Base.f() and Sub.f() because the sub class inherits its parent class's static method.
But I want to use only Base.f(), and don't want to use Sub.f() in my code.
Base.f() and Sub.f() do the same thing in the following case.
If both Base.f() and Sub.f() are used in my code, it just makes my code complex and difficult to find the places where f() are used.
Is it possible to tell swift to generate a compile error if Sub.f() is used?
Or, is there an alternative way to do it other than to define f() as a global function?
class Base {
static func f() {
print("hello world")
}
}
class Sub: Base {
}
Base.f()
// hello world
Sub.f()
// hello world
EDIT
More meaningful example than printing "hello world".
In the following case, I don't want to call it with Sub1.findSubclassByType("sub2") because Sub1 finding a subclass sounds funny.
So, I want to always call it with Base.findSubclassByType("sub2").
Maybe, defining findSubclassByType(type) in Base is a wrong design of a class? (Although, it is convenient that Xcode suggests findSubclassByType(type) when I type Base..)
What should I do?
class Base {
static func findSubclassByType(_ type: String) -> Base {
// find and return a subclass
if type == "sub1" {
return Sub1()
} else if type == "sub2" {
return Sub2()
} else {
fatalError("no sub class")
}
}
}
class Sub1: Base {
}
class Sub2: Base {
}
The comments of my question contains many good answers:
there is no dedicated swift feature to prevent subclasses from inheriting super class static methods.
move static functions to a new (final) class or struct
use class instead of static (=final class) and override the class method and add #available(*, unavailable) to it.
use Lint tools
I think the easiest way is to create a new (final) class for static methods which do not depend on subclasses, though, that sacrifices code completion feature a little.
I hope someday Swift will introduce #noInherit static func attribute.
EDIT
I found another way to restrict the way to call a static method in runtime:
class Base {
static func f() {
if Self.self != Base.self {
fatalError("don't call from subclass: " + String(describing: Self.self))
}
print("hello world")
}
}
note: The disadvantage of the EDIT is that it is checked only in runtime. The benefit of it is that you need only 3 lines and you don't need to override the static method in all subclasses. But this way should be used only when you have confident that checking in runtime is enough and safe for your app.
What you're precisely asking is impossible, because the only public/internal members that are not inherited by subclasses are initializers—and only when a subclass defines its own designated initializer, without implementations of all of its superclass's initializers.
So, to abuse that capability, you can use failable initializers when you don't need a return value…
class Base {
init() { }
#discardableResult init?(printingHelloWorld: Void) {
print("hello world")
return nil
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
Base(printingHelloWorld: ())
…or throwing initializers, when you do.
class Base {
init() { }
struct Error: Swift.Error {
let payload: String
}
init(returningAPayload: #autoclosure () -> Never) throws {
throw Error(payload: "💰")
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
extension Never {
init() { fatalError() }
}
do {
try Base(returningAPayload: .init())
} catch {
(error as! Base.Error).payload
}
I advise against any of this, and subclassing in general.

delegating initializers in structs are not marked with 'convenience'

I keep getting this error and I don't understand why.
error: delegating initializers in structs are not marked with 'convenience'
This is what I have (as an example), a DeprecatedCurrency and a SupportedCurrency.
struct DeprecatedCurrency {
let code: String
}
struct SupportedCurrency {
let code: String
}
I then want to add a convenience init function for converting from the deprecated currency object to the new currency object. And this is what I have:
struct DeprecatedCurrency {
let code: String
}
struct SupportedCurrency {
let code: String
convenience init(_ currecny: DeprecatedCurrency) { // error!!
self.init(code: currecny.code)
}
init(code: String) {
self.code = code
}
}
What does this error even mean and how do I fix it?
I know that if we don't provide a default initializer, a initializer with signature init(code: String) will be automatically generated for us with struct in Swift. So by the end of the day, what I am really looking for is (if possible):
struct SupportedCurrency {
let code: String
convenience init(_ currecny: DeprecatedCurrency) { // error!!
self.init(code: currecny.code)
}
}
Just remove the convenience, it is not required for struct.
From Swift documentation.
Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers.
They haven't mentioned using convenience. It is convenience in semantic but doesn't require the keyword.
struct DeprecatedCurrency {
let code: String
}
struct SupportedCurrency {
let code: String
init(_ currency: DeprecatedCurrency) { // error!!
self.init(code: currency.code)
}
init(code: String) {
self.code = code
}
}
structs don't need the word convenience
Try this:
struct SupportedCurrency {
let code: String
init(_ currency: DeprecatedCurrency) { // error!!
self.init(code: currency.code)
}
init(code: String) {
self.code = code
}
}
The question is not why don't we put convenience for structs but why do we put convenience for classes. The reason is that classes have inheritance. With a class you need to call the super class's designated constructor (not sure if that is the correct terminology, it comes from Objective-C's initialsers.. The word convenience marks the constructor as "not the designated constructor".
One option is to add the new init in an extension of your struct. This way, you wont loose the default auto generated memberwise initialiser.
struct SupportedCurrency {
let code: String
}
extension SupportedCurrency {
init(_ currency: DeprecatedCurrency) {
self.init(code: currency.code)
}
}
From Apple docs
NOTE
If you want your custom value type to be initializable with the
default initializer and memberwise initializer, and also with your own
custom initializers, write your custom initializers in an extension
rather than as part of the value type’s original implementation. For
more information, see Extensions.

Why can't I call protocol method from class method?

The code below compiles just fine if I make the tester() method an instance method. How can I make it work while keeping it a class method?
protocol Numbers {
}
extension Numbers {
func amountFromText(text: String) -> Int {
return 0
}
}
class CommonDB: Numbers {
class func tester() {
let text = ""
let amount = amountFromText(text)
}
}
The way you have your function defined in your protocol means that it will be an instance function, that is, you need an instance of the class or structure in order to call that function. When you are in a class function, you don't have an instance of that class.
If you want to call amountFromText() from a class function, then declare it to be static. That way, it won't need an instance of the class or structure to be called:
extension Numbers {
static func amountFromText(text: String) -> Int {
return 0
}
}

How to define initializers in a protocol extension?

protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels i get the error
Error: variable 'self' passed by reference before being initialized
How can I define the initializer in the protocol extension?
As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.
You can make another initializer a requirement so the compiler knows that all properties are initialized:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
As of Xcode 7.3 beta 1 it works with structs as expected but not with classes since if they are not final the init(wheels: Int) in the protocol is a required init and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class final.
Another workaround (in depth; without final class)
To work with classes without making them final you can also drop the init(wheels: Int) requirement in the protocol. It seems that it behaves no different than before but consider this code:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
So if you make a Car from a generic context where the type on which you call init is only to be known as Car the extension initializer is called even though an initializer is defined in HoverCar. This only occurs because there is no init(wheels: Int) requirement in the protocol.
If you add it you have the former problem with declaring the class as final but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.
Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)
My understanding is that this isn't possible, because the protocol extension can't know which properties the conforming class or struct has - and therefore cannot guarantee they are correctly initialized.
If there are ways to get around this, I'm very interested to know! :)
#Qbyte is correct.
In addition, you can take a look at my Configurable
In that I have Initable protocol
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(#noescape block: Self -> Void) {
self.init()
block(self)
}
}
Then in order to conform to it
extension Robot: Initable { }
I have 2 ways, using final or implement init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
May not be the same but in my case instead of using init I used a static func to return the object of the class.
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
Then to create the object I do something like:
let user = User.object(fromJSON:json) as? User
I know its not the best thing ever but its the best solution I could find to not couple business model with the data layer.
NOTE: I'm lazy and I coded everything directly in the comment so if something doesn't work let me know.

What is the difference between static func and class func in Swift?

I can see these definitions in the Swift library:
extension Bool : BooleanLiteralConvertible {
static func convertFromBooleanLiteral(value: Bool) -> Bool
}
protocol BooleanLiteralConvertible {
typealias BooleanLiteralType
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}
What's the difference between a member function defined as static func and another one defined as class func? Is it simply that static is for static functions of structs and enums, and class for classes and protocols? Are there any other differences that one should know about? What is the rationale for having this distinction in the syntax itself?
To be clearer, I make an example here,
class ClassA {
class func func1() -> String {
return "func1"
}
static func func2() -> String {
return "func2"
}
}
/* same as above
final class func func2() -> String {
return "func2"
}
*/
static func is same as final class func
Because it is final, we can not override it in subclass as below:
class ClassB : ClassA {
override class func func1() -> String {
return "func1 in ClassB"
}
// ERROR: Class method overrides a 'final` class method
override static func func2() -> String {
return "func2 in ClassB"
}
}
Is it simply that static is for static functions of structs and enums, and class for classes and protocols?
That's the main difference. Some other differences are that class functions are dynamically dispatched and can be overridden by subclasses.
Protocols use the class keyword, but it doesn't exclude structs from implementing the protocol, they just use static instead. Class was chosen for protocols so there wouldn't have to be a third keyword to represent static or class.
From Chris Lattner on this topic:
We considered unifying the syntax (e.g. using "type" as the keyword), but that doesn't actually simply things. The keywords "class" and "static" are good for familiarity and are quite descriptive (once you understand how + methods work), and open the door for potentially adding truly static methods to classes. The primary weirdness of this model is that protocols have to pick a keyword (and we chose "class"), but on balance it is the right tradeoff.
And here's a snippet that shows some of the override behavior of class functions:
class MyClass {
class func myFunc() {
println("myClass")
}
}
class MyOtherClass: MyClass {
override class func myFunc() {
println("myOtherClass")
}
}
var x: MyClass = MyOtherClass()
x.dynamicType.myFunc() //myOtherClass
x = MyClass()
x.dynamicType.myFunc() //myClass
I did some experiments in playground and got some conclusions.
TL;DR
As you can see, in the case of class, the use of class func or static func is just a question of habit.
Playground example with explanation:
class Dog {
final func identity() -> String {
return "Once a woofer, forever a woofer!"
}
class func talk() -> String {
return "Woof woof!"
}
static func eat() -> String {
return "Miam miam"
}
func sleep() -> String {
return "Zzz"
}
}
class Bulldog: Dog {
// Can not override a final function
// override final func identity() -> String {
// return "I'm once a dog but now I'm a cat"
// }
// Can not override a "class func", but redeclare is ok
func talk() -> String {
return "I'm a bulldog, and I don't woof."
}
// Same as "class func"
func eat() -> String {
return "I'm a bulldog, and I don't eat."
}
// Normal function can be overridden
override func sleep() -> String {
return "I'm a bulldog, and I don't sleep."
}
}
let dog = Dog()
let bullDog = Bulldog()
// FINAL FUNC
//print(Dog.identity()) // compile error
print(dog.identity()) // print "Once a woofer, forever a woofer!"
//print(Bulldog.identity()) // compile error
print(bullDog.identity()) // print "Once a woofer, forever a woofer!"
// => "final func" is just a "normal" one but prevented to be overridden nor redeclared by subclasses.
// CLASS FUNC
print(Dog.talk()) // print "Woof woof!", called directly from class
//print(dog.talk()) // compile error cause "class func" is meant to be called directly from class, not an instance.
print(Bulldog.talk()) // print "Woof woof!" cause it's called from Bulldog class, not bullDog instance.
print(bullDog.talk()) // print "I'm a bulldog, and I don't woof." cause talk() is redeclared and it's called from bullDig instance
// => "class func" is like a "static" one, must be called directly from class or subclassed, can be redeclared but NOT meant to be overridden.
// STATIC FUNC
print(Dog.eat()) // print "Miam miam"
//print(dog.eat()) // compile error cause "static func" is type method
print(Bulldog.eat()) // print "Miam miam"
print(bullDog.eat()) // print "I'm a bulldog, and I don't eat."
// NORMAL FUNC
//print(Dog.sleep()) // compile error
print(dog.sleep()) // print "Zzz"
//print(Bulldog.sleep()) // compile error
print(bullDog.sleep()) // print "I'm a bulldog, and I don't sleep."
To declare a type variable property, mark the declaration with the static declaration modifier. Classes may mark type computed properties with the class declaration modifier instead to allow subclasses to override the superclass’s implementation. Type properties are discussed in Type Properties.
NOTE
In a class declaration, the keyword static has the same effect as marking the declaration with both the class and final declaration modifiers.
Source: The Swift Programming Language - Type Variable Properties
Both the static and class keywords allow us to attach methods to a class rather than to instances of a class. For example, you might create a Student class with properties such as name and age, then create a static method numberOfStudents that is owned by the Student class itself rather than individual instances.
Where static and class differ is how they support inheritance. When you make a static method it becomes owned by the class and can't be changed by subclasses, whereas when you use class it may be overridden if needed.
Here is an Example code:
class Vehicle {
static func getCurrentSpeed() -> Int {
return 0
}
class func getCurrentNumberOfPassengers() -> Int {
return 0
}
}
class Bicycle: Vehicle {
//This is not allowed
//Compiler error: "Cannot override static method"
//static override func getCurrentSpeed() -> Int {
//return 15
//}
class override func getCurrentNumberOfPassengers() -> Int {
return 1
}
}
This example will clear every aspect!
import UIKit
class Parent {
final func finalFunc() -> String { // Final Function, cannot be redeclared.
return "Parent Final Function."
}
static func staticFunc() -> String { // Static Function, can be redeclared.
return "Parent Static Function."
}
func staticFunc() -> String { // Above function redeclared as Normal function.
return "Parent Static Function, redeclared with same name but as non-static(normal) function."
}
class func classFunc() -> String { // Class Function, can be redeclared.
return "Parent Class Function."
}
func classFunc() -> String { // Above function redeclared as Normal function.
return "Parent Class Function, redeclared with same name but as non-class(normal) function."
}
func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
return "Parent Normal Function."
}
}
class Child:Parent {
// Final functions cannot be overridden.
override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
}
override class func classFunc() -> String { // Class function, can be overidden.
return "Child Class Function."
}
override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
}
override func normalFunc() -> String { // Normal function, can be overridden.
return "Child Normal Function."
}
}
let parent = Parent()
let child = Child()
// Final
print("1. " + parent.finalFunc()) // 1. Can be called by object.
print("2. " + child.finalFunc()) // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc() // Cannot be called by class name directly.
// Child.finalFunc() // Cannot be called by class name directly.
// Static
print("3. " + parent.staticFunc()) // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc()) // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc()) // 5. Can be called by class name directly.
print("6. " + Child.staticFunc()) // 6. Can be called by class name direcly, parent(static) function will be called.
// Class
print("7. " + parent.classFunc()) // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc()) // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc()) // 9. Can be called by class name directly.
print("10. " + Child.classFunc()) // 10. Can be called by class name direcly, child(class) function will be called.
// Normal
print("11. " + parent.normalFunc()) // 11. Can be called by object.
print("12. " + child.normalFunc()) // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc() // Cannot be called by class name directly.
// Child.normalFunc() // Cannot be called by class name directly.
/*
Notes:
___________________________________________________________________________
|Types------Redeclare------Override------Call by object------Call by Class|
|Final----------0--------------0---------------1------------------0-------|
|Static---------1--------------0---------------0------------------1-------|
|Class----------1--------------1---------------0------------------1-------|
|Normal---------0--------------1---------------1------------------0-------|
---------------------------------------------------------------------------
Final vs Normal function: Both are same but normal methods can be overridden.
Static vs Class function: Both are same but class methods can be overridden.
*/
Output:
According to the Swift 2.2 Book published by apple:
“You indicate type methods by writing the static keyword before the method’s func keyword. Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method.”
From Swift2.0, Apple says:
"Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class:"
This is called type methods, and are called with dot syntax, like instance methods. However, you call type methods on the type, not on an instance of that type. Here’s how you call a type method on a class called SomeClass: