CGPoint does not conform to custom protocol in Swift - ios

I have this custom protocol, named DMPoint.
protocol DMPoint {
// MARK: - Properties
var x: Double { get set }
var y: Double { get set }
// MARK: - Lifecycle
init(x: Double, y: Double)
}
I create an extension of the CGPoint which implements the DMPoint. By analysing the documentation for CGPoint, CGPoint should conform to DMPoint without any further implementation.
extension CGPoint: DMPoint { }
If I write this piece of code, I get the following error: Type 'CGPoint' does not conform to protocol 'DMPoint'.
I have also used CGFloat for the data type used in DMPoint. It works for the CGPoint extension, but I also want to use this protocol for another classes that use Double instead of CGFloat, in which case those will also throw the same error. As of Swift 5.5, the compiler should be able to use to automatically convert CGFloat to Double and vice-versa.
I am using Swift 5.7.2. Is there any other way of making CGPoint conform to DMPoint other than using CGFloat instead of Double inside the DMPoint protocol?

In CoreFoundation, CGPoint uses Double (which is probably what you are seeing in the documentation), but in UIKit, for example, they are CGFloat.
Depending upon your use case, you might consider defining DMPoint to have an associatedtype, e.g.:
protocol DMPoint {
associatedtype FloatType
// MARK: - Properties
var x: FloatType { get set }
var y: FloatType { get set }
// MARK: - Lifecycle
init(x: FloatType, y: FloatType)
}
extension CGPoint: DMPoint { }
And if you need to have properties that always return Double, you can write an extension that defines distinct computed properties that return the Double values, but adding some constraint on the associated type, e.g.:
protocol DMPoint where FloatType: BinaryFloatingPoint {
associatedtype FloatType
// MARK: - Properties
var x: FloatType { get set }
var y: FloatType { get set }
// MARK: - Lifecycle
init(x: FloatType, y: FloatType)
}
extension CGPoint: DMPoint { }
And because of the magic of SE-0307, you can do things like:
let x: Double = point.x
Or, I guess you could write a protocol extension with default implementations to do this for you:
extension DMPoint {
var doubleX: Double {
get { Double(x) }
set { x = FloatType(newValue) }
}
var doubleY: Double {
get { Double(y) }
set { y = FloatType(newValue) }
}
func xy() -> (Double, Double) {
(doubleX, doubleY)
}
}
And then you could do things like:
let x = point.doubleX
Or:
let (x, y) = point.xy()
The other alternative is to make DMPoint a concrete type, rather than a protocol, and, for example, give it a cgPoint computed property to bridge to CGPoint, e.g.:
struct DMPoint: Codable {
// MARK: - Properties
var x: Double
var y: Double
// MARK: - Lifecycle
init(x: Double, y: Double) {
self.x = x
self.y = y
}
init(cgPoint: CGPoint) {
x = Double(cgPoint.x)
y = Double(cgPoint.y)
}
var cgPoint: CGPoint {
get { CGPoint(x: x, y: y) }
set { x = Double(newValue.x); y = Double(newValue.y) }
}
}
extension CGPoint {
var dmPoint: DMPoint {
DMPoint(cgPoint: self)
}
}

Related

Generic class of generic class with one argument/parameter

I have this syntactical issue with my data structure. What makes it worse is that I can not talk about it in detail. The company I am employed at operates in the public transportation sector and I am under NDA and boss would kill me if I posted anything too specific. I hope you understand!
I have this perfect example though. There are no inconsistencies at all ;)
Well, okay, there are. However I am convinced that most of you out there are smart enough to get what is of importance here.
Basic structure:
class Propulsion {
var horsePower: Double
init(horsePower: Double) {
self.horsePower = horsePower
}
static let pedes = Propulsion(horsePower: 0.2)
}
class Motor: Propulsion {
var range: Double
init(range: Double, horsePower: Double) {
self.range = range
super.init(horsePower: horsePower)
}
static let otto = Motor(range: 1000, horsePower: 100)
static let electric = Motor(range: 400, horsePower: 200)
}
class Vehicle<P: Propulsion> {
var propulsion: P
init(propulsion: P) {
self.propulsion = propulsion
}
}
class Bicycle<P: Propulsion>: Vehicle<P> {
var hasFrontSuspension: Bool
init(hasFrontSuspension: Bool, propulsion: P) {
self.hasFrontSuspension = hasFrontSuspension
super.init(propulsion: propulsion)
}
}
class Car<P: Propulsion>: Vehicle<P> {
func rangePerHorsePower() -> Double where P: Motor {
propulsion.range / propulsion.horsePower
}
}
Now I would like to declare a parking spot for a car. Like so:
var carParkingSpot: ParkingSpot<Car<Motor>>
For the class ParkingSpot I have some class like this in mind:
class ParkingSpot<V: Vehicle<P>> where P: Propulsion {
var vehicle: Vehicle<P>
init(vehicle: Vehicle<P>) {
self.vehicle = vehicle
}
func taxForRange() -> Double where P: Motor {
vehicle.propulsion.range * 50
}
}
From the last bit I get back a bunch of
Cannot find type 'P' in scope
This one doesn’t work either:
class ParkingSpot<V: Vehicle<P: Propulsion>>
Expected '>' to complete generic argument list
This implementation works though:
class ParkingSpot<V: Vehicle<P>, P: Propulsion> {
var vehicle: Vehicle<P>
init(vehicle: Vehicle<P>) {
self.vehicle = vehicle
}
func taxForRange() -> Double where P: Motor {
vehicle.propulsion.range * 50
}
}
However I don’t want to duplicate the Motor bit:
var carParkingSpot: ParkingSpot<Car<Motor>, Motor>
How can I accomplish this with just one generic parameter?
You may use the "Protocol oriented" approach:
protocol PropulsionP {
var horsePower: Double { get }
}
protocol MotorP: PropulsionP {
var range: Double { get }
}
struct MotorS: MotorP {
var range: Double
var horsePower: Double
init(range: Double, horsePower: Double) {
self.range = range
self.horsePower = horsePower
}
}
protocol VehicleP {
associatedtype P: PropulsionP
var propulsion: P { get }
}
struct BicycleS<Prop: PropulsionP>: VehicleP {
let hasFrontSuspension: Bool
var propulsion: Prop
init(
hasFrontSuspension: Bool,
propulsion: Prop
) {
self.hasFrontSuspension = hasFrontSuspension
self.propulsion = propulsion
}
}
struct CarS<Prop: PropulsionP>: VehicleP {
var propulsion: Prop
func rangePerHorsePower() -> Double where P: MotorP {
propulsion.range / propulsion.horsePower
}
}
struct ParkingSpotS<V: VehicleP> {
var vehicle: V
init(vehicle: V) {
self.vehicle = vehicle
}
func taxForRange() -> Double where V.P: MotorP {
vehicle.propulsion.range * 50
}
}
var carParkingSpot: ParkingSpotS<CarS<MotorS>>
No double MotorS bit.
Quod erat demonstrandum.
I used the somewhat unusual naming to emphasize the point.
(needed to make some edit, erronously typed Motor where I actually need MotorP)
Update
I was on the road with my preferred car and tried it out:
var carParkingSpot: ParkingSpotS<CarS<MotorS>> = .init(
vehicle: .init(
propulsion: .init(
range: 760,
horsePower: 240
)
)
)
print(carParkingSpot.taxForRange())
38000.0
Alternatively you can use this initialiser:
var carParkingSpot: ParkingSpotS = .init(
vehicle: CarS(
propulsion: MotorS(
range: 760,
horsePower: 240
)
)
)
Update
Now suppose you are utilising a third party library which already provides a nice implementation of a motor.
What you need to do is to implement an extension for their given class or struct TheirMotor which conforms to your protocol MotorP:
import FancyMotors
extension TheirMotor: MotorP {
let range: Double {
// calculate `range` in terms of the
// given API of `TheirMotor`:
...
return range
}
}
Then, you can use it like below:
var carParkingSpot: ParkingSpotS = .init(
vehicle: CarS(
propulsion: TheirMotor(
distance: 760,
power: 240
)
)
)
Note, that you use TheirMotor and need to use the appropriate initialiser to create it.
This seems to work:
class ParkingSpot<V: Vehicle<Propulsion>>
{
var vehicle: V
init(vehicle: V)
{
self.vehicle = vehicle
}
func taxForEngineeNoise() -> Double
{
switch vehicle.propulsion
{
case is Motor:
return vehicle.propulsion.horsePower * 50
default:
...
}
}
func taxForRange() -> Double
{
if let motor = vehicle.propulsion as? Motor
{
return motor.range * 50
}
else
{
...
}
}
}
Alternatively, perhaps hide the duplication where you can?
typealias ParkingSpotX = ParkingSpot<Car<Motor>, Motor>
var parkingSpot: ParkingSpotX

Make a swift protocol conform to Hashable

I'm going around in circles trying to get Hashable to work with multiple struct that conform to the same protocol.
I have a protocol SomeLocation declared like this:
protocol SomeLocation {
var name:String { get }
var coordinates:Coordinate { get }
}
Then I create multiple objects that contain similar data like this:
struct ShopLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
init(from decoder: Decoder) throws {
...
}
}
struct CarLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
init(from decoder: Decoder) throws {
...
}
}
I can later use these in the same array by declaring:
let locations: [SomeLocation]
The problem is, I create an MKAnnotation subclass and need to use a custom Hashable on the SomeLocation objects.
final class LocationAnnotation:NSObject, MKAnnotation {
let location:SomeLocation
init(location:SomeLocation) {
self.location = location
super.init()
}
}
override var hash: Int {
return location.hashValue
}
override func isEqual(_ object: Any?) -> Bool {
if let annot = object as? LocationAnnotation
{
let isEqual = (annot.location == location)
return isEqual
}
return false
}
This gives me 2 errors:
Value of type 'SomeLocation' has no member 'hashValue' Binary operator
'==' cannot be applied to two 'SomeLocation' operands
So I add the Hashable protocol to my SomeLocation protocol:
protocol SomeLocation: Hashable {
...
}
This removes the first error of hashValue not being available, but now I get an error where I declared let location:SomeLocation saying
Protocol 'SomeLocation' can only be used as a generic constraint because it has Self or associated type requirements
So it doesn't look like I can add Hashable to the protocol.
I can add Hashable directly to each struct that implements the SomeLocation protocol, however that means I need to use code like this and keep updating it every time I might make another object that conforms to the SomeLocation protocol.
override var hash: Int {
if let location = location as? ShopLocation
{
return location.hashValue
}
return self.hashValue
}
I have tried another way, by making a SomeLocationRepresentable struct:
struct SomeLocationRepresentable {
private let wrapped: SomeLocation
init<T:SomeLocation>(with:T) {
wrapped = with
}
}
extension SomeLocationRepresentable: SomeLocation, Hashable {
var name: String {
wrapped.name
}
var coordinates: Coordinate {
wrapped.coordinates
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(coordinates)
}
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.name == rhs.name && lhs.coordinates == rhs.coordinates
}
}
however when I try to use this in the LocationAnnotation class like
let location: SomeLocationRepresentable
init(location:SomeLocation) {
self.location = SomeLocationRepresentable(with: location)
super.init()
}
I get an error
Value of protocol type 'SomeLocation' cannot conform to 'SomeLocation'; only struct/enum/class types can conform to protocols
Is it possible to achieve what I am trying to do? Use objects that all conform to a protocol and use a custom Hashable to compare one to the other?
Deriving the protocol from Hashable and using a type eraser might help here:
protocol SomeLocation: Hashable {
var name: String { get }
var coordinates: Coordinate { get }
}
struct AnyLocation: SomeLocation {
let name: String
let coordinates: Coordinate
init<L: SomeLocation>(_ location: L) {
name = location.name
coordinates = location.coordinates
}
}
You then can simply declare the protocol conformance on the structs, and if Coordinate is already Hashable, then you don't need to write any extra hashing code code, since the compiler can automatically synthesize for you (and so will do for new types as long as all their properties are Hashable:
struct ShopLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
}
struct CarLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
}
If Coordinate is also Codable, then you also can omit writing any code for the encoding/decoding operations, the compile will synthesize the required methods (provided all other properties are already Codable).
You can then use the eraser within the annotation class by forwardingn the initializer constraints:
final class LocationAnnotation: NSObject, MKAnnotation {
let location: AnyLocation
init<L: SomeLocation>(location: L) {
self.location = AnyLocation(location)
super.init()
}
override var hash: Int {
location.hashValue
}
override func isEqual(_ object: Any?) -> Bool {
(object as? LocationAnnotation)?.location == location
}
}

Swift: Properly initialize SIMD3 and call it from struct

I am trying call the defined struct so I am able to change its value when a button is pressed. I am having trouble with calling SIMD3 inside a struct. Currently I have,
struct CaptureData {
var vertices: [SIMD3<Float>]
var mode: Mode = .one
mutating func nextCase() {
mode = mode.next()
}
var verticesFormatted : String {
let v = "<" + vertices.map{ "\($0.x):\($0.y):\($0.z)" }.joined(separator: "~") + "method: \(mode.next().rawValue)"
return "\(v)"
}
}
And the extension that I got helped earlier from #Joshua
enum Mode: String, CaseIterable {
case one, two, three
}
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
var nextCase: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
#discardableResult
func next() -> Self {
return self.nextCase
}
}
I am trying to initialize var instance = CaptureData(vertices: [SIMD3<Float>]), but the error comes: Cannot convert value of type '[SIMD3<Float>].Type' to expected argument type '[SIMD3<Float>]'
#Jousha also suggested me to use the following:
typealias XYZVar = (x: Float, y: Float, z: Float)
struct CaptureData {
var vertices:[XYZVar]
.... other variables
}
However, I also tried that with var instance = CaptureData(vertices: [XYZVar]) and it also not working: Cannot convert value of type '[XYZVar].Type' (aka 'Array<(x: Float, y: Float, z: Float)>.Type') to expected argument type '[XYZVar]' (aka 'Array<(x: Float, y: Float, z: Float)>')
My question is, how to I call SIMD3 properly and fix the above error from var instance = CaptureData(vertices: [SIMD3<Float>])?
Thanks so much in advance.
Hmm, where do I start here?
You are passing [SIMD3<Float>] and [XYZVar] which are types, to a function/initializer that expects a value as a parameter. That's why the compiler is complaining.
Let me explain.
In swift when you write var vertices: [SIMD3<Float>] you are saying: "vertices" is an array of SIMD3<Float>. Now, if you want to assign a value to "vertices" you can do so by writing vertices = [] or vertices = [SIMD3<Float>]() they are equivalent.
I did some changes to your code. Take a look:
import simd
enum Mode: String, CaseIterable {
case one, two, three
}
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
var nextCase: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
#discardableResult
func next() -> Self {
return self.nextCase
}
}
struct CaptureData {
var vertices: [SIMD3<Float>]
var mode: Mode = .one
mutating func nextCase() {
mode = mode.next()
}
var verticesFormatted : String {
let verticesDescribed = vertices
.map({ "\($0.x):\($0.y):\($0.z)" })
.joined(separator: "~")
let v = "< \(verticesDescribed) method: \(mode.next().rawValue)"
return v
}
}
let data = CaptureData(vertices: [
SIMD3<Float>(x: 0, y: 0, z: 0),
SIMD3<Float>(x: 0.5, y: 1, z: 0),
SIMD3<Float>(x: 1, y: 0, z: 0)
])
print(data.verticesFormatted)
// prints: < 0.0:0.0:0.0~0.5:1.0:0.0~1.0:0.0:0.0 method: two

How can I write a simple example on how to use delegates in Swift 5

I want to write a simple example on how delegates work in Swift. I've set up a class, a protocol and another class which adheres to the protocol. However I'm getting on two different places the same error. I've created a simple swift command line tool in xcode and all my code is inside main.swift. The code has no real functionality except learning how delegates work.
Here are the error messages:
Consecutive declarations on a line must be separated by ';'
Insert ';'
Expected '(' in argument list of function declaration
Expected '{' in body of function declaration
Expected 'func' keyword in instance method declaration
Insert 'func '
Expected declaration
Invalid redeclaration of 'delegate()' //or anything() in the other error
Here is the code:
class MainClass {
var delegate: MyProtocol? = nil
delegate.doAnything() //getting 1st error here
}
protocol MyProtocol {
func doAnything()
}
class OtherClass: MyProtocol {
let anything = MainClass()
anything?.delegate = self //getting 2nd error here
func doAnything() {
print("text")
}
}
So the first error is because you are trying to call the delegate function, outside of anywhere it can be executed. You need to create a function that calls that function, or call it in init. When making examples, try using real world concepts to model your example. You could do something like a Conductor class and a Train Class. The conductor could implement some control protocol that controls the speed of the train.
Anyway, your second error is because self has not yet been initialized. to assign a variable to self, you must initialize the class first, so you could do
init() {
anything?.delegate = self
}
Feel free to DM to understand this concept more, i'll post a full example here in a bit.
EDIT: FULL EXAMPLE, feel free to ask questions
import Foundation
enum Direction {
case north
case east
case south
case west
}
protocol VehicleControls {
var speed: Float {get set}
var direction: Direction {get set}
var numPassengers: Int {get}
func change(newSpeed: Float)
func change(newDirection: Direction)
func createNoise()
}
class Conductor {
var vehicle: VehicleControls
init() {
vehicle = Train(s: 1.5, d: .west, nP: 50)
}
func controlVehicle() {
vehicle.change(newSpeed: 2.5)
vehicle.change(newDirection: .east)
vehicle.createNoise()
print("\n")
}
}
class Train: VehicleControls {
var speed: Float
var direction: Direction
var numPassengers: Int
init() {
self.speed = 0
self.direction = .north
self.numPassengers = 0
}
init(s: Float, d: Direction, nP: Int) {
self.speed = s
self.direction = d
self.numPassengers = nP
}
func change(newSpeed: Float) {
print("changing speed from \(speed), to \(newSpeed)")
self.speed = newSpeed
}
func change(newDirection: Direction) {
print("changing direction from \(direction) to \(newDirection)")
self.direction = newDirection
}
func createNoise() {
print("Chugga, Chugga... Chugga, Chugga... CHOO CHOO")
}
}
class Car: VehicleControls {
var speed: Float
var direction: Direction
var numPassengers: Int
init() {
self.speed = 0
self.direction = .north
self.numPassengers = 0
}
init(s: Float, d: Direction, nP: Int) {
self.speed = s
self.direction = d
self.numPassengers = nP
}
func change(newSpeed: Float) {
print("changing speed from \(speed), to \(newSpeed)")
self.speed = newSpeed
}
func change(newDirection: Direction) {
print("changing direction from \(direction) to \(newDirection)")
self.direction = newDirection
}
func createNoise() {
print("HONK HONK, BEEP BEEP")
}
}
let newConductor = Conductor()
newConductor.controlVehicle()
newConductor.vehicle = Car(s: 60.56, d: .north, nP: 2)
newConductor.controlVehicle()
edit your code in playground file:
protocol MyProtocol {
func doAnything()
}
class MainClass {
var delegate: MyProtocol? = nil
func callMeForGetCallBackWithDelegate() {
// send call back inside any function after call or inside in init
if let delegate = self.delegate {
delegate.doAnything()
}
}
}
class OtherClass: MyProtocol {
let anything = MainClass()
init() {
self.anything.delegate = self // set delegate in init or set inside any function
self.anything.callMeForGetCallBackWithDelegate()
}
func doAnything() {
print("text")
}
}
let otherClass = OtherClass()

Convert custom type to CGFloat in swift

I have my own little class:
class EPPercent {
init(_: CGFloat) {
}
}
Now I want to convert an element of this class to CGFloat:
var percent: Any = 0
percent = EPPercent(100)
var toCGFloat = CGFloat(percent)
This gives an Error:
"Cannot invoke initializer for type 'CGFloat' with an argument list of type '(EPPercent)'"
How do I do this?
Thank you for your help ;)
You can create an extension of CGFloat and create a custom initializer that accepts an EPPercent instance.
class EPPercent {
let value: CGFloat
init(_ value: CGFloat) {
self.value = value
}
}
extension CGFloat {
init(_ percent: EPPercent) {
self = percent.value
}
}
var percent = EPPercent(100)
var toCGFloat = CGFloat(percent)
Let me know in case you face any issues.

Resources