Swift use protocol extension defaults - swift

I have
protocol ErrorContent {
var descriptionLabelText: String { get set }
}
extension ErrorContent {
var descriptionLabelText: String { return "Hi" }
}
struct LoginErrorContent: ErrorContent {
var descriptionLabelText: String
init(error: ApiError) {
...
}
}
and xcode is complaining that "Return from initializer without initializing all stored properties." What I want here is to just use the default value that I gave the descriptionLabelText in the protocol extension. Isn't that the point of protocol extensions? Anyways I'd like to understand why this is wrong and what I can do to use my default value.

Almost correct, just a couple of issues with your code:
You don't need to declare the variable in LoginErrorContent, as the implementation is already in the ErrorContent extension. Declaring it again overrides the extension implementation
If you want to use the extension computed property for descriptionLabelText, you can't specify that it is a setter, as it only returns a value.
Example:
protocol ErrorContent {
var descriptionLabelText: String { get }
}
extension ErrorContent {
var descriptionLabelText: String { return "Hi" }
}
struct LoginErrorContent: ErrorContent {
// Overriding the extension behaviour
var descriptionLabelText: String { return "Hello" }
init(error: ApiError) {
...
}
}

Related

DRY code: how to call an implementation from another protocol

I have some code I want to DRY up, I don't want to repeat/maintain the same code at multiple places.
protocol Programable {
var log: String { get }
}
protocol Convertable {
var status: String { get set }
}
extension Programable where Self: NSManagedObject {
var log: String {
return <managed object related stuff>
}
}
extension Programable where Self: NSManagedObject, Self: Convertable {
var log: String {
return <managed object related stuff> + status
}
}
How can I call the first extension's log in the second extension, so I don't have to repeat the details in the code?
It is impossible to call the same overload if only the constraints differ. Instead, move the commonality into something private. There is no naming convention for this.
extension Programmable where Self: AnyObject {
var log: String { where_Self_is_AnyObject_log }
private var where_Self_is_AnyObject_log: String { "where Self: AnyObject" }
}
extension Programmable where Self: AnyObject & Convertible {
var log: String { "\(where_Self_is_AnyObject_log) & Convertible" }
}

How to refactor this code with static init variables?

I have a static class like this:
class CDService {
static var initVar:Type?
static var var2:Type2? = {
return initVar?.someProp
}
static func method() {
var2?.doSomething()
}
//....a lot more methods all using var2?
}
Because initVar is optional (require the user to set it before using this service), now var2 has to be optional too.
And then all the methods in this class all of a sudden requires unwrapping. They are use a lot.
Is there a way to refactor this code to just not run if initVar is not yet? I could do a "if let" check in each method but its really tedious. If there is 50 methods?
You can use optional extensions to give default values , I've tried, it's comes really handy when using default datatype optionals.
extension Optional where Wrapped == String { // same goes for other data types
var orEmpty: String {
return self ?? ""
}
var orDash: String {
return self ?? "-"
}
var orZero: String {
return self ?? "0"
}
}
or in your case
extension Optional where Wrapped == Type2 {
var orEmpty: Type2 {
return self ?? Type2()
}
}

Generics in protocols

I have a UnitDimension class given by:
class UnitDimension: {
var symbol: String
init(symbol: String) {
self.symbol = symbol
}
}
and a UnitVolume subclass of this class:
class UnitVolume: UnitDimension {
static let liter = UnitVolume(symbol: "L")
}
I want to have a protocol UnitDimensionHandler that allows me to perform some simple functions. Firstly it must have an allUnits variable:
protocol UnitDimensionHandler: class {
static var allUnits: [UnitDimension] { get }
}
Is it possible to have allUnits a generic type of array that must be a subclass of UnitDimension? I could then implement it in UnitVolume as follows:
extension UnitVolume: UnitDimensionHandler {
static var allUnits: [UnitVolume] {
return [liter]
}
}
I then want to include a function that also allows me to use a generic subclass type that initiates a UnitDimension instance:
extension UnitDimensionHandler {
static func unit(for symbol: String) -> UnitDimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
such that UnitVolume.unit(for: "L") returns an optional UnitVolume rather than an optional UnitDimension.
Thanks for any help.
Yes it is possible, using associatedtype:
protocol UnitDimensionHandler: class {
// here we define `generic` type variable `Dimension`, and specify it do be descendant of `UnitDimension`
associatedtype Dimension: UnitDimension
// and use it here, instead of `UnitDimension`
static var allUnits: [Dimension] { get }
}
And
extension UnitDimensionHandler {
// same `UnitDimension` -> `Dimension` replacement
static func unit(for symbol: String) -> Dimension? {
return allUnits.first() { $0.symbol == symbol }
}
}

Swift struct extensions: 'Cannot convert return expression of type <type> to return type <type>'

Let's say you have the following structs and protocols:
struct Ticket {
var items: [TicketItem] = []
}
struct TicketItem {
}
protocol DisplayableTicket {
var displayedItems: [DisplayableTicketItem] { get }
}
protocol DisplayableTicketItem {}
Now, if I were to extend those structs like so:
extension Ticket: DisplayableTicket {
var displayedItems: [DisplayableTicketItem] {
return self.items
}
}
extension TicketItem: DisplayableTicketItem {}
I get the following error on the line return self.items:
Cannot convert return expression of type '[TicketItem]' to return type 'DisplayableTicketItem'
If I change the type of Ticket and TicketItem to class, I don't get an error. Why can't the Ticket struct contain an array of TicketItem structs and be extended as described above?
Like this:
extension Ticket: DisplayableTicket {
var displayedItems: [DisplayableTicketItem] {
return self.items.map{$0 as DisplayableTicketItem}
}
}

Swift extension declaration error: "declaration only valid at file scope"

I'm trying to create a simple Swift extension containing a calculated property. I don't understand why I'm getting this compile error (“declaration only valid at file scope”). The error is at the beginning of the "private extension OpStack" line. (This code is contained in a class.)
If I remove all of the code inside the extension, I still get the same error.
Here's the code:
private typealias OpStack = Array<Op>
private extension OpStack {
//^ error:"This declaration is only valid at file scope"
var topIsOperation: Bool {
if self.isEmpty { return false }
switch self[self.count-1] {
case .Operand:
return false
default:
return true
}
}
}
The problem is extension Array<> { } works, extending Arrays, but extension Array<SomeType> { } does not work because its trying to extend some particular arrays with elements of type SomeType instead of all arrays.
I solved the problem by using a struct instead of trying to extend Array:
struct OpStack {
var ops = [Op]()
var topIsOperation: Bool {
if self.ops.isEmpty { return false }
switch self.ops[self.ops.count-1] {
case .Operand:
return false
default:
return true
}
}
}
Alternatively, I could have created a function:
func topIsOperation(a: [op]) -> bool { }