Swift protocol conform: Candidate has non-matching type
A playground example of what you can do:
class SomeClass {
}
class Subclass : SomeClass{
}
protocol TestProtocol {
typealias T : SomeClass
var prop: [T] {get}
}
class Test: TestProtocol {
var prop = [Subclass]()
func test(){
prop.append(Subclass())
}
}
let test = Test()
test.test()
print(test.prop) // prints "[Subclass]\n"
Candidate has non-matching type of 'clearly matching type'
The answer I got to:
I'm not sure why I cannot expose the variable as it is. User
isn't a protocol; it's just a subclass of NSManagedObject
.
And I tested exposing a simple bool
from the class and it worked just fine.
But in the end exposing the whole User
object isn't quite wise, because I might need to pull all its dependencies in the dependent module even though the module itself doesn't use all of them.
So I:
- declared a protocol (in the dependent module) used to expose what I need from
User
public protocol ModuleUser {
var id: Int64
}
- used that in the dependent protocol:
public protocol LoginAPIManagerProtocol {
...
var moduleUser: ModuleUser? { get }
...
}
- and the conformance:
extension APIManager: LoginAPIManagerProtocol, LoginProtocol {
var moduleUser: ModuleUser? {
return self.user
}
}
And now I don't need to add the User
object to the dependent module anymore; which is noice :D
Swift: Candidate has non-matching type
func numberOfSlicesInPieChartView(pieChartView: PieChartView) -> CInt {
return 32
}
func pieChartView(pieChartView: PieChartView, colorForSliceAtIndex index: UInt) -> UIColor {
return UIColor(red: 1.0, green: 0, blue: 0, alpha: 1)
}
func pieChartView(pieChartView: PieChartView, valueForSliceAtIndex index: UInt) -> Double {
return 100/3;
}
Use -> CInt
instead of Int
because Swift Int
could not be converted to C int
. Same as Double
-> CDouble
Use index: UInt
instead of index: Int
, because NSUInteger
is unsigned.
Swift protocol property of type Set Self
The way to put constraints in protocols is similar to how you specify protocol conformance (they're the same thing after all)
protocol Groupable: Hashable
{
var parent: Self? { get }
var children: Set<Self> { get }
}
Swift - Conform third-party type to my own protocol with conflicting requirement
Inspired by Jonas Maier's comment, I found what I believe to be an architecturally adequate solution to this problem. As Jonas said, function overloading exhibits the behavior that I'm looking for. I'm starting to think that maybe protocol requirements should only ever be functions, and not properties. Following this line of thinking, my protocol will now be:
protocol CursorInput {
func getCursorLocation () -> CGPoint
func setCursorLocation (_ newValue: CGPoint)
}
(Note that in this answer I'm making it settable as well, unlike in the original post.)
I can now retroactively conform AATrackpad
to this protocol without conflict:
extension AATrackpad: CursorInput {
func getCursorLocation () -> CGPoint {
return CGPoint(x: self.cursorLocation.x, y: self.cursorLocation.y)
}
func setCursorLocation (_ newValue: CGPoint) {
self.cursorLocation = AAPoint(newValue)
}
}
Important - This will still compile even if AATrackpad
already has a function func getCursorLocation () -> AAPoint
, which has the same name but a different type. This behavior is exactly what I was wanting from my property in the original post. Thus:
The major problem with including a property in a protocol is that it can render certain concrete types literally incapable of conforming to that protocol due to namespace collisions.
After solving this in this way, I have a new problem to solve: there was a reason I wanted cursorLocation
to be a property and not a function. I definitely do not want to be forced to use the getPropertyName()
syntax all across my app. Thankfully, this can be solved, like this:
extension CursorInput {
var cursorLocation: CGPoint {
get { return self.getCursorLocation() }
set { self.setCursorLocation(newValue) }
}
}
This is what is so cool about protocol extensions. Anything declared in a protocol extension behaves analogously to a default argument for a function - only used if nothing else takes precedence. Because of this different mode of behavior, this property does not cause a conflict when I conform AATrackpad
to CursorInput
. I can now use the property semantics that I originally wanted and I don't have to worry about namespace conflicts. I'm satisfied.
"Wait a second - now that AATrackpad
conforms to CursorInput
, doesn't it have two versions of cursorLocation
? If I were to use trackpad.cursorLocation
, would it be a CGPoint
or an AAPoint
?
The way this works is this - if within this scope the object is known to be an AATrackpad
then Alice's original property is used:
let trackpad = AATrackpad()
type(of: trackpad.cursorLocation) // This is AAPoint
However, if the type is known only to be a CursorInput
then the default property that I defined gets used:
let cursorInput: CursorInput = AATrackpad()
type(of: cursorInput.cursorLocation) // This is CGPoint
This means that if I do happen to know that the type is AATrackpad
then I can access either version of the property like this:
let trackpad = AATrackpad()
type(of: trackpad.cursorLocation) // This is AAPoint
type(of: (trackpad as CursorInput).cursorLocation) // This is CGPoint
and it also means that my use case is exactly solved, because I specifically wanted not to know whether my cursorInput
happens to be an AATrackpad
or a BBMouse
- only that it is some kind of CursorInput
. Therefore, wherever I am using my cursorInput: CursorInput?
, its properties will be of the types which I defined in the protocol extension, not the original types defined in the class.
There is one possibility that a protocol with only functions as requirements could cause a namespace conflict - Jonas pointed this out in his comment. If one of the protocol requirements is a function with no arguments and the conforming type already has a property with that name then the type will not be able to conform to the protocol. This is why I made sure to name my functions including verbs, not just nouns (func getCursorLocation () -> CGPoint
) - if any third-party type is using a verb in a property name then I probably don't want to be using it anyway :)
Related Topics
How to Reduce the Opacity of the Shadows in Realitykit
Http Request Swift Providing Parameters
Why Do We Need to Set Delegate to Self? Why Isn't It Defaulted by the Compiler
Response Struct Does Not Like Codingkeys
Making Button Span Across VStack
How to Calculate the Energy Per Bin in a Dft
How to Use Tabs to Evenly Space Out Description Strings in Swift
How to Segue Values When My Viewcontroller Is Embedded in an Uinavigationcontroller
Deep Copy of Cmimagebuffer or Cvimagebuffer
Why Does Somestruct() Is Anyobject Return True
Concatenate Literal with Optional String
How to Handle Parameter Validation Swift
Uisegment Value Changing When Tableview Get Scrolled
How to Reference the View's Window in Swift 3.X Using Storyboards/Cocoa
Use Quick Look Inside a Swift Cocoa Application to Preview Audio Files
Inline Kvo of a Property in Another View Controller
Hittest Prints Ar Entity Name Even When I am Not Tapping on It
How to Add a Left Bar Button Without Overriding the Natural Back Button