Create a protocol with default implementation that gives name/title/self of Enum as string - ios

I am trying to create a protocol with default implementation that returns enum itself as string. But not able to find the correct syntax.
This is the code I tried so far, but it is not taking default implementation
protocol TestSelf {
static var desc: String { get set }
}
extension TestSelf {
get {
static var desc: String {
String(describing: self)
}
set {
print(\(new value))
}
}
enum Test: TestSelf { }
Access
print(Test.desc)
Asking me to implement the desc in the enum saying 'static var' declaration requires an initializer expression or an explicitly stated getter. I don't want to initialize it again. It should work with Default Implementation.
Ask:
At all places I don't need to write
String(describing: Test.self)
instead I can directly use
Test.desc

I think you want something like this (this is playground code):
protocol SelfDescriber {
static var descriptionOfSelf: String {get}
}
extension SelfDescriber {
static var descriptionOfSelf: String {
String(describing: Self.self)
}
}
enum Test: SelfDescriber {}
print(Test.descriptionOfSelf) // "Test"

Related

How to initialize WidgetInfo for unit testing in Xcode?

I am trying to initialize the WidgetKit struct WidgetInfo for unit testing a function that takes WidgetInfo as an argument:
let widgetInfo = WidgetInfo()
This gives me the error:
'WidgetInfo' cannot be constructed because it has no accessible initializers
I tried adding:
extension WidgetInfo {
public init() {}
}
and I can initialize - yay! But then I try to set one of its properties
widgetInfo.family = .systemSmall
and get the error: Cannot assign to property: 'family' is a 'let' constant
I tried another initializer with arguments:
extension WidgetInfo {
public init(family: WidgetFamily, kind: String) {
self.family = family
self.kind = kind
}
}
and I get the error: 'let' property 'family' may not be initialized directly; use "self.init(...)" or "self = ..." instead
I'm stuck - is there a way for me to initialize WidgetInfo? Or another way to test a function that takes WidgetInfo as an argument?
Figured it out. I created a WidgetInfo protocol with the information I needed, changed the function to take the protocol as the argument and extended WidgetInfo:
protocol WidgetInfoProtocol {
var widgetFamily: WidgetFamily { get }
var widgetKind: String { get }
}
extension WidgetInfo: WidgetInfoProtocol {
var widgetFamily: WidgetFamily {
return family
}
var widgetKind: String {
return kind
}
}
This allowed me to create a mock for use in unit testing:
struct MockWidgetInfo: WidgetInfoProtocol {
var widgetFamily: WidgetFamily
var widgetKind: String
}

Protocols and Enums in Swift with Apollo

I am using Apollo for Swift in an iOS app. I have multiple types that all represent the same object. These types are auto-generated from a schema file and look something like this.
struct CurrentUser {
var id: String
...
}
struct MyUser {
var id: String
...
}
Basically Apollo generates multiple Swift types (one for each query) for the same underlying data type.
I want to create a new struct that unifies these types.
I would like to do something like this:
protocol UserProtocol {
var id: String { get }
}
struct User {
var id: String
...
init(_ data: UserProtocol) {
self.id = data.id
...
}
}
This approach however gives me an error when I try to construct a user object, telling me that "Type MyUser does not conform to UserProtocol". If I try to coerce the type with data as! UserProtocol I get a crash.
The only solution I've found is the following:
enum UserType {
case .currentUser(CurrentUser)
case .myUser(MyUser)
}
struct User {
var id: String
...
init(_ data: UserType) {
switch data {
case .myUser(let user):
self.id = data.id
...
case .currentUser(let user):
self.id = data.id
...
}
}
}
This approach works, but it leads to a lot of duplicated code in the init function. Is there a better way to do this in Swift?
I suspect the problem is that you need to explicitly conform the Apollo generated types to your protocol:
extension CurrentUser: UserProtocol { }
extension MyUser: UserProtocol { }
Remember that Swift is not duck-typed like some other languages, so a type with member var id: String is not UserProtocol until you declare it as such.
If for some reason you need to do some transformation of the Apollo types to fit the app models in the future, those extensions are a good place to do that, too.

Swift correct use of getters and setters

Can someone please help me understand the correct use of getters and setters in swift. I get the impression its not the same as say Java.
Is this the correct usage in Swift to store and access a class variable?
class Person {
private var name: String
init(name: String) {
self.name = name
}
func setName(name: String) {
self.name = name
}
func getName() -> String {
return name
}
}
Swift provides a much more structured approach to getters and setters than Java.
You can, but you should not, write setters and getters as you did in your code.
Instead (if you are using stored properties) just declare the property with a visibility non private (e.g. internal in my example). This way callers outside of your class will be able to see the property and change it.
class Person {
var name: String {
willSet(newValue) {
print("\(self.name) is going to be renamed as \(newValue)")
}
didSet(oldValue) {
print("\(oldValue) has been renamed as \(self.name)")
}
}
init(name: String) {
self.name = name
}
}
Ok but in java getter and setters do allow me to add custom logic to be executed before or after the value is changed.
Right! In Swift, you can do this using the willSet and didSet observers.
willSet(newValue)
You write here the code you want to run before a new value is written in the property.
Here you can access the current value (that is going to be overwritten) with self.name while the new value is available with newValue.
didSet(oldValue)
You write here the code you want to run after a new value is written in the property.
Here you can access the old value (that has been overwritten) with oldValue while the new value is available in self.name.
Both willSet and didSet are optional [I am not talking about Optional Type! I mean you are not forced to write them :)].
If you don't need to run some code just before or after the property has been changed, just omit them.
Example
let aVerySmartPerson = Person(name: "Walter White")
aVerySmartPerson.name = "Heisenberg"
// > Walter White is going to be renamed as Heisenberg
// > Walter White has been renamed as Heisenberg
If you assign to self., you will just be calling this method again. Also, there is no "get" like the old Java bean property pattern. Finally, if you actually need to use methods for property computation or actions after setting, they can be built right into the variable definition.
class Person
{
private var name: String;
init( name: String )
{
self.name = name
}
}
should be sufficient for your simple case, although you can also
private var name: String {
didSet {
// updating something after setting
}
};
This is how setter and getter works as in Java:
class Person {
private var _name
private var _age
// .... other properties
var name: String {
get {
return _name
}
set {
_name = newValue
}
}
var age: String {
get {
return _age
}
set {
_age = newValue
}
}
}

A static field inherited from the base class or protocol - how?

I want to be able to have the classes which have a static property (field) which is either inherited from the base class or "mixed" from a protocol. And every class should have it's own implementation of that property. Is it possible? Preferably, it to be immutable.
class C1 {
static let stProperty = "my prorepty1"
}
class C2 {
static let stProperty = "my prorepty2"
}
It's possible, but it's really hard to make this useful in Swift. How do you plan to refer to this property? Let's start with a super-simple implementation:
protocol SomeProtocol {
static var prop: String { get }
}
class C1: SomeProtocol {
static let prop = "This is One"
}
Great. So now I want a function that uses this:
func useProp(x: SomeProtocol) -> String {
return x.prop
// 'SomeProtocol' does not have a member named 'prop'
}
That doesn't work. x is an instance, but I want the type.
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
func useProp(x: SomeProtocol.Type) -> String {
return x.prop
}
This is probably how it will work some day given the word "unimplemented." But it doesn't work today.
func useProp(x: SomeProtocol) -> String {
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
return x.dynamicType.prop
}
Same thing.
Today, you really have to hang this on the object itself and not use static or class:
protocol SomeProtocol {
var prop: String { get }
}
class C1: SomeProtocol {
let prop = "This is One"
}
func useProp(x: SomeProtocol) -> String {
return x.prop
}
That's not so terrible in many cases, since the value for the class is probably also the value for any given instance of the class. And it's really all we can do today.
Of course your problem might be that you don't have an instance yet and you need this information to build an instance. That's really hard today and you should probably rethink your design. You'll generally have to use some other pattern like a Builder. See Generic Types Collection for more.
Now you also said:
or "mixed" from a protocol
I wouldn't say "mixed" here. If you really mean this like a Ruby "mixin", there is no such thing in Swift today. Swift folks often refer to this feature as "default implementation," and it's not currently possible (though I do expect it to come eventually). The only thing you can do in the protocol is say that the implementor has to provide this method somehow. You can't provide it for them.
Sure you can do that with a protocol:
protocol SomeProtocol {
static var foo: String { get }
}
class One: SomeProtocol {
class var foo: String {
get {
return "This is One"
}
}
}
Btw I agree with Rob Napier below that this is a bit off a oddball feature. I do think there are probably use-cases for it, but I also think those can be better implemented with other language features
protocol P {
class var stProperty: String { get }
}
class C1 {
class var stProperty: String {
return = "my property1"
}
}
class C2 {
class var stProperty: String {
return = "my property2"
}
}
Usage:
C2.prop //"my property2"
If you try:
C2.prop = "new value" //"cannot assign to the result of this expression"

Swift - Typealias dictionary with value that implements a generic protocol

I want to typealias a dictionary of String keys and values of objects/structs that implements the Equatable protocol. So I wrote this line of code but it gave me error that I didn't know how to go on to fix.
typealias Storage = [String: Equatable]
I want to use the type [String: Equatable] as a variable in a protocol, e.g:
protocol StorageModel {
var storage: Storage { get set }
init(storage: Storage)
}
Error:
Protocol 'Equatable' can only be used as a generic constraint because
it has Self or associated type requirements
Can anyone suggest a solution?
Generally speaking, the protocol tag isn't required, protocol names are first-class type names and can be used directly:
typealias Storage = [String:Equatable]
In this case, what the error is telling you is that because Equatable includes func == (lhs:Self, rhs:Self) -> Bool and specifically lhs:Self, Equatable can't be used except as a constraint on a generic:
class Generic<T:Equatable> { ... }
Without more details about what you're trying to achieve and how you're trying to use StorageModel, the best I can come up with is:
protocol Matches {
typealias T
func matches(t:T) -> Bool
}
protocol StorageModel {
typealias T
var storage: [String:T] { get set }
init(storage:[String:T])
}
extension Int : Matches {
func matches(target:Int) -> Bool {
return self == target
}
}
class MyClass <T:Matches> {
var model = [String:T]()
}
Another possibility is to use a generic instead of a protocol:
class StorageModel <T:Equatable> {
var storage: [String:T]
init(storage:[String:T]) {
self.storage = storage
}
}
From there you'll need to do some research, dig into the Swift manual, do some googling and see what solves your problem.

Resources