Why Swift class need init but not Swift struct - swift

The below code, where one is for Struct, the other is for Class.
I'm wondering why we need init for class and not struct (although we can add one to it)? Is there any technical reason behind that an init is required in class, but more relax in struct?
struct StructTest {
private let value: Int
}
class ClassTest {
private let value: Int
init(value: Int) {
self.value = value
}
}

Structs still have an initializers. The only differences is that in some cases the compiler will synthesize a "default member-wise initalizer" for you.
In this case, it created one with the signititure private init(value: Int) (private because your struct has a private field)

Related

How to define func to a specific case of Enum in Swift?

enum Type {
case A
case B
func do() {
}
}
I would like do for available for case A
I don't think what you want is possible with enums.
However, it can be done with tricks.
First, create a class called Type:
class Type { private init() {} }
And create two classes, AType and BType to inherit Type:
// Put this in the same file as Type
class AType: Type { private init() {} }
class BType: Type { private init() {} }
The private initializer is to prevent external code to create AType and BType objects.
In Type, add these static properties:
static let A = AType()
static let B = BType()
Then you're basically done!
To add a method that only Type.A is accessible, just add it in the AType class!
This way, just like an enum, Type.A and Type.B can still be assigned to a Type object!

Why Swift requires override of designated initializer of generic superclass?

According to Apple's documentation Swift does not necessary require override of initializer. In a following code example Bar inherits initializer of Foo:
class Foo {
let value: Int
init(value: Int = 5) {
self.value = value
}
}
class Bar: Foo {
}
As soon as we add some generic into Foo such as class Foo<T> { Xcode provides us a error Initializer does not override a designated initializer from its superclass. Is there a documentation or swift evolution discussion that explains why it is happening?
Update. It seems that generic is not a major cause for override requirement. Here are an option how to define a class with generic that does not require override of designated initializer:
protocol FooProtocol {
associatedtype T
}
class Foo<U>: FooProtocol {
typealias T = U
let value: Int
init(value: Int, otherValue: T) {
self.value = value
self.otherValue = otherValue
}
}
class Bar: Foo<Int> {
}
However there is another interesting observation of behavior. Defining initializer like following cause override requirement:
init(value: Int = 5) {
self.value = value
}
The funny thing thing that adding one more parameter as following into such designated initializer cause this override requirement to disappear:
init(value: Int = 5, otherValue: T) {
self.value = value
}
Update 2. I can not find a logical explanation to this behavior, at this point I reported it as Compiler bug — https://bugs.swift.org/browse/SR-1375
I actually filled a bug report for inheriting from generic class:
It was back in November last year and didn't get an answer yet, so ¯_(ツ)_/¯
It's clearly a bug. Moreover, although the bug is elicited by subclassing a generic, its proximate cause is the default value. This compiles just fine:
class Foo<T> {
let value: Int
init(value: Int) {
self.value = value
}
}
class Bar: Foo<String> {
}
But this does not:
class Foo<T> {
let value: Int
init(value: Int = 5) {
self.value = value
}
}
class Bar: Foo<String> {
}
That sort of arbitrary distinction without a difference is a sure indication that this is a compiler bug.

Initialising a class from a number Swift

A range of basic classes in the foundation framework can be made by simply assigning a basic number to the value where the desired type is known take for example CGFloat:
let a: CGFloat = 42
instead of having to simply use an init like so:
let a = CGFloat(42)
My question is what is this called when a struct or a class implements this behaviour and how can it be implemented for your own classes.
I don't believe this is matter of CGFloat being a type alias and I cannot seem to find a suitable answer for this.
Your type would need to implement the IntegerLiteralConvertible protocol.
That protocol requires you to implement a constructor of the form:
init(integerLiteral value: Self.IntegerLiteralType) {}
Example:
struct MyCoolStruct {
let value: Int
}
extension MyCoolStruct : IntegerLiteralConvertible {
init(integerLiteral value: Int) {
self.value = value
}
}
let instance: MyCoolStruct = 3
instance.value
Swift 4/5:
IntegerLiteralConvertible has been renamed in ExpressibleByIntegerLiteral:
extension MyStruct: ExpressibleByIntegerLiteral {
init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}

Swift - store values in map. Different behaviour in structs vs classes

This example Swift code does not compile if SomeClass is defined as struct. The compiler says: #value $T6 is not identical to (String, Proto)
However, the compiler does not complain if SomeClass is a class.
Why?
public protocol Proto {
func hello(value:Int)
}
public struct SomeClass {
var map = [String:Proto]()
public func store (key:String, value:Proto) {
map[key] = value // That does not work if SomeClass is a struct
}
}
Because you modify the element of the struct in the store function, and if you do so, you have to add the "mutating" prefix to it.
So:
public mutating func store (key:String, value:Proto) {
map[key] = value // That does not work if SomeClass is a struct
}
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method.

whats the swift equivalent of NSObject<Protocol>?

I have a class that needs to be set with a variable of a NSObject subclass and that implements a certain protocol.
protocol ProtoTest {
var foo: Int { get set }
}
class AClass: NSObject, ProtoTest {
var foo: Int = 3
}
class BClass: NSObject, ProtoTest {
var foo: Int = 4
}
class Consumer {
var protoInstance: ProtoTest? //Does not cary any information of the class just the protocol
var protoInstance2: protocol<NSObjectProtocol, ProtoTest>?
init(x: ProtoTest) {
self.protoInstance = x
self.protoInstance2 = nil
}
init(x: protocol<NSObjectProtocol, ProtoTest>) {
self.protoInstance2 = x
self.protoInstance = nil
}
func doSomething() {
if let x = protoInstance {
x.copy() //'ProtoTest' does not have a member named 'copy'
}
if let x = protoInstance2 {
x.copy() //protocol<NSObjectProtocol, ProtoTest> does not have a member named 'copy'
}
}
}
In the example above, neither declarations of the variable are gonna work. since neither of them have any knowledge of a base class?
How do I implement this in swift ?
The usual equivalent of NSObject<Protocol> in Swift is simply Protocol. Typically, this protocol is declared as a class protocol to guarantee that it will be adopted by a class.
If you also need the NSObject protocol methods (such a respondsToSelector:, then make Protocol adopt NSObjectProtocol.
If the problem is merely that you want to call copy() and you can't persuade the compiler to let you do it, then adopt NSCopying as well (or just use respondsToSelector: and performSelector: to bypass the compiler altogether).
You can do this a couple of ways. First, you can make Consumer generic:
class Consumer<T: NSObject where T: Prototest> {
var protoInstance: T?
var protoInstance2: T?
}
If you do that, then all references to protoInstance or protoInstance2 will inherit from NSObject, and you will be able to call methods like .copy() directly on the object.
If you don't want Consumer to be generic, you can enforce restraints on the init methods using generic parameters, like this:
class Consumer {
// ...
init<T: NSObject where T: Prototest>(x: T) {
protoInstance = x
}
}
If you do that, you will be guaranteed that protoInstance will be an NSObject, but you will have to cast to NSObject to use any of NSObject's methods:
func doSomething() {
if let x = protoInstance as? NSObject {
x.copy()
}
}
Edit:
Note that I wasn't sure if you really wanted protoInstance and protoInstance2 to be of different types I was a little unclear from your question. If you do want them to be different types, I can add additional suggestions to this answer.