Extending structs with protocols in Swift - ios

I have the following piece of code. The protocols and extensions I've added don't seem to be doing quite what I expect. What am I missing?
struct foo {
var getFoo: String
var getBar: bar
struct bar {
var getBar: String
}
}
protocol FooProtocol {
var getFoo: String { get }
var getBar: BarProtocol { get }
}
extension foo: FooProtocol {} // Type 'foo' does not conform to protocol 'FooProtocol'
protocol BarProtocol {
var getBar: String { get }
}
extension foo.bar: BarProtocol {}
The problem in this code is the line extension foo: FooProtocol {}, where we're trying to say that, in effect foo.getBar.getBar should be a valid property. However, Xcode throws up a compilation error saying "Type 'foo' does not conform to protocol 'FooProtocol'.
I can fix this by changing the following:
protocol FooProtocol {
var getFoo: String { get }
var getBar: foo.bar { get } // instead of var getBar: BarProtocol { get }
}
However, it seems the line extension foo.bar: BarProtocol {} should mean FooProtocol doesn't care if we give it foo.bar or BarProtocol. What am I missing here?
#Drobs answer was correct. Here's a bonus question.
BONUS
Now suppose I need to implement another struct that conforms to FooProtocol. Neither of these approaches work. What's the fix?
struct FooImplementation: FooProtocol { // Type 'FooImplementation' does not conform to protocol 'FooProtocol'
var getFoo: String
var getBar: BarProtocol
}
Do I need to use some sort of typealias to achieve this?

You want to use an associatedtype in the protocol. In that case it essentially says give me a type that implements the protocol BarProtocol.
protocol FooProtocol {
associatedtype BarType: BarProtocol
var getFoo: String { get }
var getBar: BarType { get }
}
protocol BarProtocol {
var getBar: String { get }
}
struct Foo: FooProtocol {
var getFoo: String
var getBar: Bar
struct Bar: BarProtocol {
var getBar: String
}
}

Related

Swift different default implementations for protocol property

I know that you can give a default value with a protocol extension like this
protocol SomeProtocol {
var prop: String { get }
}
extension SomeProtocol {
var prop: String {
return "defaultValue"
}
}
struct SomeA: SomeProtocol {}
struct SomeB: SomeProtocol {}
let a = SomeA()
let b = SomeB()
debugPrint(a.prop) // prints defaultValue
debugPrint(b.prop) // prints defaultValue
but is there a way to have different default value for different implementations of the protocol like this without implementing the property for every class or struct that conforms to this protocol?
debugPrint(a.prop) // prints defaultValue
debugPrint(b.prop) // prints differentDefaultValue
or some similar pattern for doing something like this?
Protocol inheritance.
protocol 😺: SomeProtocol { }
extension 😺 {
var prop: String { "😺" }
}
struct SomeA: SomeProtocol { }
struct SomeB: 😺 { }
struct SomeC: 😺 { }
SomeA().prop // "defaultValue"
SomeB().prop // "😺"
SomeC().prop // "😺"

Swift conform to protocol subclass

Within my app, I have multiple UIView subclasses that depend on a model. Each of the classes adopting 'Restorable' protocol which holds the superclass of the model. Each sub-model describes the specific UIView not-common properties.
// Super-model
public protocol StoryItem {
var id: Int64? { get }
}
// Parent protocol
public protocol Restorable: AnyObject {
var storyItem: StoryItem? { get set }
}
// Specific protocol
public struct TextItem: StoryItem {
public var id: Int64?
public var text: String?
}
// Not complling
class ResizableLabel: UILabel, Restorable {
var storyItem: TextItem?
}
I'm getting the following compiler error:
*Type 'ResizableLabel' does not conform to protocol 'Restorable'*
The only way I can make it compile is by changing ResizableLabel to
// Works
class ResizableLabel: UILabel, Restorable {
var storyItem: StoryItem?
}
Is there any way to conform to protocol subclass? it'll make the Init process much cleaner. Thank you for your help!
Change
public protocol Restorable: AnyObject {
var storyItem: StoryItem? { get set } // adopter must declare as StoryItem
}
to
public protocol Restorable: AnyObject {
associatedtype T : StoryItem
var storyItem: T? { get set } // adopter must declare as StoryItem adopter
}
Now your code compiles. Full example:
public protocol StoryItem {
var id: Int64? { get }
}
public protocol Restorable: AnyObject {
associatedtype T : StoryItem
var storyItem: T? { get set }
}
public struct TextItem: StoryItem {
public var id: Int64?
public var text: String?
}
class ResizableLabel: UILabel, Restorable {
var storyItem: TextItem? // ok because TextItem is a StoryItem adopter
}

Add class property to protocol in Swift

I want to have a protocol that have a variable. And class that conform to that protocol should use it like "normal" variable. What i want is something like:
protocol MyProtocol {
var foo: Int
}
class A {}
extension A: MyProtocol {
var foo: Int!
}
Code above not compile, i only want to show point i want to achieve.
I ended up with this, but i suppose there must be better way:
enum NextController {
case AuthSelection
case Main
}
protocol SmsEntryPresenterProtocol {
var nextController: NextController { get set }
}
class SmsEntryPresenter {
var _nextController: NextController!
weak var view: SmsEntryViewProtocol?
}
extension SmsEntryPresenter: SmsEntryPresenterProtocol {
var nextController: NextController {
get {
return _nextController
}
set {
_nextController = newValue
}
}
}
You can fix this as below,
class SmsEntryPresenter {
var nextController: NextController = .Main
weak var view: SmsEntryViewProtocol?
}
extension SmsEntryPresenter: SmsEntryPresenterProtocol {}

Weak property requirement in Swift protocol with associated type

I want to write a protocol with weak property requirement. Class that conforms it must be able to specify any type for this property. Also I don't want to specify an actual type, so it should be a type specified with some protocol. This code shows my idea for non-weak property:
protocol ObjectProtocol: class {
typealias PropertyType
var property: PropertyType {get set}
}
protocol FirstPropertyProtocol: class {}
protocol SecondPropertyProtocol: class {}
class FirstObjectImpl: ObjectProtocol {
var property: FirstPropertyProtocol?
}
class SecondObjectImpl: ObjectProtocol {
var property: SecondPropertyProtocol?
}
It works as expected.
I tried to do the same for weak property:
protocol ObjectProtocol: class {
typealias WeakPropertyType: AnyObject //must be a class type
weak var weakProperty: WeakPropertyType? {get set}
}
protocol WeakPropertyProtocol: class {}
class ObjectImpl: ObjectProtocol {
weak var weakProperty: WeakPropertyProtocol?
}
And I got a compiler error:
Type 'ObjectImpl' does not conform to protocol 'ObjectProtocol'
Is there any way I can make this work?
I made it work with #objc attribute for WeakPropertyProtocol:
protocol ObjectProtocol: class {
typealias WeakPropertyType: AnyObject //must be a class type
weak var weakProperty: WeakPropertyType? {get set}
}
#objc protocol WeakPropertyProtocol {}
class SomeObjectImpl: ObjectProtocol {
weak var weakProperty: WeakPropertyProtocol?
}
It's not a best solution because I concern about this note from apple doc
Note also that #objc protocols can be adopted only by classes that
inherit from Objective-C classes or other #objc classes.
I can live with this restriction but I will appreciate any better solution.
I don't believe a protocol can enforce weak-ness. For example:
protocol ObjectProtocol: class {
weak var weakProperty: AnyObject? {get set}
}
class ObjectImpl1: ObjectProtocol {
weak var weakProperty: AnyObject?
}
class ObjectImpl2: ObjectProtocol {
var weakProperty: AnyObject?
}
These both compile ok, even though the protocol has weak but ObjectImpl2 does not implement it.
EDIT: Is this what you're after?...
protocol ObjectProtocol: class {
typealias WeakPropertyType: Any //must be a class type
var weakProperty: WeakPropertyType? {get set}
}
protocol WeakPropertyProtocol: class {}
class ObjectImpl: ObjectProtocol {
typealias WeakPropertyType = WeakPropertyProtocol
weak var weakProperty: WeakPropertyProtocol?
}
This implementation requires use of Any rather than AnyObject, since WeakPropertyProtocol is a protocol rather than a class.
Or this?...
protocol WeakPropertyProtocol: class {}
protocol ObjectProtocol: class {
typealias WeakPropertyType: AnyObject //must be a class type
var weakProperty: WeakPropertyType? {get set}
}
class MyWeakClass: WeakPropertyProtocol {
}
class ObjectImpl: ObjectProtocol {
typealias WeakPropertyType = MyWeakClass
weak var weakProperty: MyWeakClass?
}
Either way, I think the key is in defining which class/protocol to use for WeakPropertyType.
As Swift 5.7, bundled with Xcode 14.0, the compiler emits the error: "'weak' cannot be applied to a property declaration in a protocol"
A possible protocol limitation workaround uses a computed variable and a supplementary 'weak' variable wrapped by the computed variable.
Workaround 1: This workaround doesn't force types that apply the protocol to set the property to weak
protocol SharedInformation {
var name: UIViewController? { get set }
}
class Country: SharedInformation {
private weak var _name: UIViewController?
var name: UIViewController? {
get {
_name
}
set {
_name = newValue
}
}
}
Workaround 2: This one forces a type that applies the protocol to have the property wrapped with weak storage.
protocol SharedInformation {
var name: Weak<UIViewController> { get set }
}
class Country: SharedInformation {
var name: Weak<UIViewController> = .init()
func usage() {
// set
name.wrappedValue = UIViewController()
// get
let value = name.wrappedValue
}
}
public struct Weak<Wrapped: AnyObject> {
public weak var wrappedValue: Wrapped?
public init(_ value: Wrapped? = nil) {
self.wrappedValue = value
}
}
Swift 4 version.
I needed my view models to conform to a protocol. They mustn't retain a coordinator object:
protocol ViewModelType {
associatedtype CoordinatorType: AnyObject
weak var coordinator: CoordinatorType? { get }
}

Swift array of struct types conforming to protocol

I have a series of several structs conforming to MyProtocol. I need an array of these structs' types (because they have a static method declared in MyProtocol that I need to be able to access). I have tried all kinds of things but I can't make Xcode like it.
Also, before this is marked as dupe – I tried this, but all I got was:
//Foo and Bar are structs conforming to MyProtocol
let MyStructArray: Array<MyProtocol.self> = [Foo.self, Bar.self]
//Protocol 'MyProtocol' can only be used as a generic constant because it has Self or associated type requirements
How about this?:
protocol MyProtocol {
static func hello()
}
struct Foo: MyProtocol {
static func hello() {
println("I am a Foo")
}
var a: Int
}
struct Bar: MyProtocol {
static func hello() {
println("I am a Bar")
}
var b: Double
}
struct Baz: MyProtocol {
static func hello() {
println("I am a Baz")
}
var b: Double
}
let mystructarray: Array<MyProtocol.Type> = [Foo.self, Bar.self, Baz.self]
(mystructarray[0] as? Foo.Type)?.hello() // prints "I am a Foo"
for v in mystructarray {
switch(v) {
case let a as Foo.Type:
a.hello()
case let a as Bar.Type:
a.hello()
default:
println("I am something else")
}
}
// The above prints:
I am a Foo
I am a Bar
I am something else
I found the problem. My protocol was inheriting from RawOptionSetType. Not sure why that caused an issue, but commenting that inheritance out made it work. Weird.

Resources