How to implement a Swift protocol across structs with conflicting property names
The desired feature from explicit interface implementations is that they are statically dispatched, right? If you use Description
on a BusStop
, it will be an optional string, but if you use Description
on a Stop
, it will be a non-optional string.
In Swift, extension members are statically dispatched, so you can make use of this to achieve something similar:
extension Stop where Self == BusStop {
// Since the type of "self" here is BusStop, "Description" refers to the one declared in BusStop
// not this one here, so this won't cause infinite recursion
var Description : String { return self.Description ?? "" }
}
extension Stop where Self == TrainStop {
var Latitude: Double { return self.Latitude ?? 0 }
var Longitude: Double { return self.Longitude ?? 0 }
}
This code shows that this works:
let busStop = BusStop(Code: "ABC", Description: "My Bus Stop", Latitude: 0, Longitude: 0)
print(type(of: busStop.Description)) // Optional<String>
let stop: Stop = busStop
print(type(of: stop.Description)) // String
However, I still don't think this is good Swift code. It is often bad to just directly translate an API from one language to another. If I were you, I would make Longitude
, Latitude
and Description
in Stop
to be all optionals.
swift protocol conformance when same property name is optional
There is no elegant solution to your problem other than renaming the conflicting property on the conforming type.
Swift doesn't allow 2 properties of the same name to exist on a type even if their types are different. On the other hand, Int?
and Int
are completely different types, so you cannot have trackNumber: Int
fulfil the protocol requirement of trackNumber: Int?
.
The only solution (other than changing the type in either the protocol
or the struct
) is to rename the non-Optional property in SpotifyTrack
and make an optional computed property of the same name returning the non-optional one.
protocol Track {
var trackNumber: Int? { get }
}
struct SpotifyTrack {
private let _trackNumber: Int
}
extension SpotifyTrack: Track {
var trackNumber: Int? { _trackNumber }
}
How can I explicitly implement a protocol in swift? If it is impossible, why?
Protocol extensions basically already do what you're describing:
protocol Cat {
}
extension Cat {
func quack() {
print("meow")
}
}
class Duck : Cat {
func quack() {
print("quack")
}
}
let d = Duck()
d.quack() // quack
(d as Cat).quack() // meow
Swift Struct with Lazy, private property conforming to Protocol
Because accessing the lazy data
variable mutates AStruct
, any access to it must be marked as also mutating the struct. So you need to write:
struct AStruct : Example {
// ...
var var1: String {
// must declare get explicitly, and make it mutating:
mutating get {
// act of looking at data mutates AStruct (by possibly initializing data)
return self.data.var1
}
}
var varArray:[String] {
mutating get {
return self.data.varArray
}
}
}
However, you'll find now that Swift complains you aren't conforming to Example
, because its get var1
isn't marked as mutating. So you'd have to change it to match:
protocol Example {
var var1:String { mutating get }
var varArray:[String] { mutating get }
}
How to resolve conflict between struct and module names?
The following scenario resolves name conflict between struct and module for second case which contains A, B, C projects. This solution is based on rule that we can edit only C project. Because C is our client of hypothetically third-party unchangeable modules A and B.
- Add new Swift file into C project with code below
import struct A.B
typealias StructB = B
- Change code in Src.swift to the following
import B
let structB: StructB? = nil
struct X { }
typealias Y = B.X
Result is succeeded compilation without error:
'X' is not a member type of 'B'
And we can use struct B from module A and struct from module B in single file. The name conflict has been resolved.
The second one scenario resolves conflict in the first case with Data.
- Replace
import Foundation
with
import struct Foundation.Date
import struct Foundation.UUID
- Be sure that Foundation isn't imported in module level. In my case I removed
#import <UIKit/UIKit.h>
from Data.h. And replacedFOUNDATION_EXPORT
withextern
to do Data.h compilable.
Conflicting with parent property description in Swift
As vadian suggested in comments, I decided to use Codable
protocol instead of EVReflection
as Codable
is way easy to use. I read this link for Codable
and this video link for parsing json data.
Hashable struct with interchangeable properties?
This is how Hasher works
https://developer.apple.com/documentation/swift/hasher
However, the underlying hash algorithm is designed to exhibit
avalanche effects: slight changes to the seed or the input byte
sequence will typically produce drastic changes in the generated hash
value.
So the problem here in hash(into:) func
Since the sequence matters combine
operation is not commutative. You should find some other function to be a hash for this struct. In your case the best option is
func hash(into hasher: inout Hasher) {
hasher.combine(leftOperand & rightOperand)
}
As @Martin R pointed out to have less collisions it's better to use ^
func hash(into hasher: inout Hasher) {
hasher.combine(leftOperand ^ rightOperand)
}
Related Topics
Contextmenu on a Rounded Lineargradient Produces Sharp Edges in Swiftui
Typealias of Generic Class in Swift
How to Record My MAC's Internal Sound, Not the Microphone!, Using Avcapturesession
How to Create Public Extensions, in a Shared Framework, for Xctest
Problems Accessing Calendar Using Ekeventstore on Osx Sierra with Swift 3
How to Grant Discoveruserinfowithuserrecordid Permission
Create Spotlight-Like Window in Swift 4
Timer Onreceive Not Working Inside Navigationview
Memory Problems When Switching Between Scenes Spritekit
Uiprogressview Progress Update Very Slow Within Alamofire (Async) Call
How to Create an Uppercase Version of a String in Swiftui
Swift: Overriding Typealias Inside Subclass
How to Star a Repo with Github API
Crop Image According to Rectangle in Swiftui
How to Place Objects with Hit Test Without Plane Detection