Swift protocols mutability [duplicate] - swift

This question already has answers here:
Read-only properties of protocols in Swift
(3 answers)
Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?
(3 answers)
Closed 2 years ago.
I'm currently a bit confused about gettable properties in protocols. Consider this example:
protocol Person {
var name: String { get }
}
I expected the name property to be read-only, but I found that you could change the value without compiler complaints:
struct Driver: Person {
var name: String
}
var driver = Driver(name: "Ryan")
driver.name = "Changed!"
If we define driver with let keyword, then compiler raises the error, but if I understand correctly, it has nothing to do with protocols, as constant structs are immutable by design in Swift.
Method interactions behave as I would've expected:
extension Person {
mutating func changeName(_ newName: String) {
self.name = newName // Error: 'name' is a get-only property
}
}
I'm new to Swift, and the nuance mentioned may not have any practical use, but this behavior made me ask myself if I lack some basic understanding of how structs work.

The protocol requirement is
a variable name which can be read
which doesn't mean that the variable in a struct adopting this protocol is necessarily read-only.
In the code you are changing the variable directly in the Driver type, the protocol is not involved.
On the other hand if you annotate the protocol type you get the expected error
var driver : Person = Driver(name: "Ryan")
driver.name = "Changed!" // Cannot assign to property: 'name' is a get-only property

A protocol only declares the required interface, but not the full interface of conforming types. Your conforming types can add extra properties/methods that aren't required by the protocol.
The same is true for getters and setter. If a protocol property requirement is get, that means the conformant type must have a getter for the property, but doesn't mean it cannot have a setter for it as well.
However, the same doesn't work the other way around. If a protocol declares a property as { get set }, that property must have a setter (be mutable).

The apple documentation explains this very well.
The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property.

Related

Why can't I declare dynamic variable inside protocol

I'm currently working on protocols for my objects which inherits from Realm's Object. Inside my objects I have variables and these variables are marked as #objc dynamic
#objc dynamic var title: String = ""
Now imagine situation that I have more similar objects with same variable title. I want to create protocol for them since I want to have just one generics method for changing title of object.
So, I created protocol with title variable marked as #objc dynamic with the expectation that this is how it works
protocol Titleable: class {
#objc dynamic var title: String { get set }
}
... this didn't work out and I received actually two errors.
One about marking variable as #objc
#objc can only be used with members of classes, #objc protocols, and concrete extensions of classes
... this I could solve by marking protocol as #objc.
However I still had error connected with dynamic keyword
Only members of classes may be dynamic
... I thought that when I constrained protocol for classes, it should be alright, but... it wasn't.
I somehow solved it by removing #objc as well as dynamic keywords
protocol Titleable: class {
var title: String { get set }
}
... that works. I'm able to mark variable as #objc dynamic in class where I implement this protocol.
class Item: Object, Titleable {
#objc dynamic var title: String = ""
}
However, I'm not sure why this works and why marking variable as dynamic inside protocol declaration doesn't. I would appreciate any explanation.
Look at what dynamic means:
dynamic
Apply this modifier to any member of a class that can be represented
by Objective-C. When you mark a member declaration with the dynamic
modifier, access to that member is always dynamically dispatched using
the Objective-C runtime. Access to that member is never inlined or
devirtualized by the compiler.
Because declarations marked with the dynamic modifier are dispatched
using the Objective-C runtime, they must be marked with the objc
attribute.
Particularly consider that first paragraph. It says that something that is marked dynamic cannot be statically dispatched. Now consider the case where I have some class in a module. It's already been compiled, and its methods were statically dispatched. Now consider another module that conforms that class to some protocol that includes a dynamic method. How can that work? The method has already been statically dispatched in some places. It can't retroactively be transformed into dynamic dispatch. (The same can apply to declarations in the same module depending on compiler flags and access levels, but I find it easier to explain cross-module.)
The main reason you'd want to do this in any case is to make sure you can use KVO on that property. (If you have some other reason you need to force conforming types to use a dynamic property, I'm interested to know the use case.) If that is your goal, I would probably require Titleable to conform to NSObjectProtocol.

Swift: Using getter with no value

What is the benefit of using a getter with no value. For example:
protocol xyz:Class{
var uuid:UUID{get}
}
I'll really appreciate your thoughts.
The code in your question is declaring a protocol. A protocol is basically a contract. It provides no functionality.
Your protocol's contract is stating that whatever conforms to the protocol must, at a minimum, provide a getter for a variable named uuid with a type of UUID.
The protocol itself does not provide the getter so it does not return a value. The class/struct/enum that conforms to the protocol will provide a value from the getter. This same class/struct/enum may also (if desired) provide a setter for the uuid variable as well. The protocol only states there must be a getter but it does not preclude the possibility of a setter.
The Protocols chapter in the Swift book shows examples and provides much more information on this. Specifically, the Property Requirements section covers protocol properties.

Only classes that inherit from NSObject can be declared #objc

I have to set value to property by string name representation.
import Foundation
#objc class A:NSObject {
var x:String = ""
}
var a = A()
a.x = "ddd"
print(a.x)
a.setValue("zzz", forKey:"x")
print(a.x)
And getting strange errors during compilation:
main.swift:4:2: error: only classes that inherit from NSObject can be declared #objc
#objc class A:NSObject {
~^~~~~
main.swift:13:1: error: value of type 'A' has no member 'setValue'
a.setValue("zzz", forKey:"x")
^ ~~~~~~~~
Does anyone know what is happening?
PS: reproducible on Swift 4.0 & 3.1.1 (Ubuntu 16.04.3 LTS)
Edited:
import Foundation
#objc class A:NSObject {
#objc dynamic var x:String = ""
}
var a = A()
a.x = "ddd"
print(a.x)
a.setValue("zzz", forKeyPath:"x")
print(a.x)
Output:
error: only classes that inherit from NSObject can be declared #objc
#objc class A:NSObject {
error: property cannot be marked #objc because its type cannot be represented in Objective-C
#objc dynamic var x:String = ""
note: Swift structs cannot be represented in Objective-C
#objc dynamic var x:String = ""
error: value of type 'A' has no member 'setValue'
a.setValue("zzz", forKeyPath:"x")
EDIT 2:
Just trying like "c-style":
func set<T>(_ val:T, forKey key:String) {
print("SET:\(self) \(key) to \(val)")
let ivar: Ivar = class_getInstanceVariable(type(of: self), key)!
let pointerToInstanceField:UnsafeMutableRawPointer = Unmanaged.passRetained(self).toOpaque().advanced(by: ivar_getOffset(ivar))
let pointer = pointerToInstanceField.assumingMemoryBound(to: T.self)
pointer.pointee = val
}
It works well, but causes bad access in the recursive calls. Probably some retain/release issues. Will dig dipper. Also does not work on Linux (as mentioned in answers)
Documentation
Swift without the Objective-C Runtime: Swift on Linux does not depend
on the Objective-C runtime nor includes it. While Swift was designed
to interoperate closely with Objective-C when it is present, it was
also designed to work in environments where the Objective-C runtime
does not exist.
https://swift.org/blog/swift-linux-port/
Which is clear, provided that it states:
value of type 'A' has no member 'setValue'
It basically tells that there is no KVC mechanism underneath. setValue method comes from Objective-C runtime, which is absent on Linux. Thus, it's a no-go and what you're trying to accomplish is simply not possible.
Other than that, the following rule is applied on systems with Obj-C runtime environment:
Key-Value Coding with Swift
Swift objects that inherit from NSObject or one of its subclasses are
key-value coding compliant for their properties by default. Whereas in
Objective-C, a property’s accessors and instance variables must follow
certain patterns, a standard property declaration in Swift
automatically guarantees this. On the other hand, many of the
protocol’s features are either not relevant or are better handled
using native Swift constructs or techniques that do not exist in
Objective-C. For example, because all Swift properties are objects,
you never exercise the default implementation’s special handling of
non-object properties.
Also: Requiring Dynamic Dispatch
Swift APIs that are callable from Objective-C must be available
through dynamic dispatch. However, the availability of dynamic
dispatch doesn’t prevent the Swift compiler from selecting a more
efficient dispatch approach when those APIs are called from Swift
code.
You use the #objc attribute along with the dynamic modifier to require
that access to members be dynamically dispatched through the
Objective-C runtime. Requiring this kind of dynamic dispatch is rarely
necessary. However, it is necessary when using APIs like key–value
observing or the method_exchangeImplementations function in the
Objective-C runtime, which dynamically replace the implementation of a
method at runtime.
Declarations marked with the dynamic modifier must also be explicitly
marked with the #objc attribute unless the #objc attribute is
implicitly added by the declaration’s context. For information about
when the #objc attribute is implicitly added, see Declaration
Attributes in The Swift Programming Language (Swift 4).
Elements must also be declared dynamic in order to be KVO-compatible (for KVC, inheriting from NSObject is enough):
#objc dynamic var x:String = ""
If String doesn't work out, then try going with NSString.
If neither helps, this seems to be a Linux-specific issue, which doesn't appear to support KVC/KVO mechanism (which is also understandable).
P.S. With the code provided, your issue reproduced in Xcode on Mac, too.

Why Doesn't The Swift Compiler Detect Properties of Protocols

I am using an NSOperation that conforms to SomeProtocol that has a results property
let op : NSOperation, SomeProtocol = ...
op.completionBlock = {
print(op.results)
}
I get the following error:
Value of type 'NSOperation' has no member 'results'
I know that I can subclass NSOperation to get the intended behaviour, but can I achieve what I want using protocols?
That code shouldn't even get that far... unlike Objective-C, Swift does not allow specifying a variable as a combination of both a concrete type AND a protocol. You can only declare a variable to be of a specific type, a specific protocol, or a composition of protocols, e.g.
let op : protocol<SomeProtocol, AnotherProtocol> = ...
But there is currently no way to declare a variable as being of the specific type NSOperation AND conforming to the protocol SomeProtocol

Use of a Structure instead of a Class in Swift [duplicate]

This question already has answers here:
Why Choose Struct Over Class?
(17 answers)
Closed 7 years ago.
I learn Swift from some time, I know the differences between structure and class. The main difference is structure is of value type and class is of reference type but didn't understand when to use structure instead of a class. Please explain it.
For example, In case of Protocols:
First, We have just a protocol of struct type:
protocol SomeProtocol{
func doSomeStuff()
}
Second, We make protocol of class type like this:
protocol SomeProtocol: class{
func doSomeStuff()
}
So, Please explain me, when we have to use protocol of struct type or of class type.
Firstly structs are passed by value (copied), and a class is passed by reference (copied just the memory address to the object).You may want to use structs for simpler types, because you get a free init for all the properties your struct has.And with protocols, the first one you can use it on class,struct and enum, the second you say that you only use that on classes,and you may want to put class if your protocol is a delegate or a data source,because you want the property(of the type of your protocol) weak to avoid the memory cycle. IMHO use classes for multi-scene apps because you don't need to take care to update value when you edited something in an another scene.
The protocol is not "of struct type" or "of class type", that is wrong terminology.
If you write SomeProtocol: class you make sure only classes can conform to that protocol, structs cannot. If you don't include the class both classes and structs can conform.
The docs (scroll down to "Class-Only Protocols") tell you that
You can limit protocol adoption to class types (and not structures or enumerations) by adding the class keyword to a protocol’s inheritance list. The class keyword must always appear first in a protocol’s inheritance list, before any inherited protocols.
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more on reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.