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()
}
}
Related
So because I got bored of having to manually nil-coalesce optional values, I decided to make the common default values into nice and easy-to-use extensions on Optional, as seen below:
public extension Optional {
var exists: Bool { return self != nil }
}
public extension Optional where Wrapped == String {
var orEmpty: Wrapped { return self ?? "" }
}
public extension Optional where Wrapped == Int {
var orZero: Wrapped { return self ?? 0 }
}
public extension Optional where Wrapped == Double {
var orZero: Wrapped { return self ?? 0 }
}
public extension Optional where Wrapped == Float {
var orZero: Wrapped { return self ?? 0 }
}
public extension Optional where Wrapped == Bool {
var orFalse: Wrapped { return self ?? false }
}
My issue arrives when attempting to use these on an optional value with a specific type.
I can call .orZero on a variable of type String? and get one of the following errors:
Ambiguous reference to member 'orZero'
'String?' is not convertible to 'Optional'
I'd like to know why Xcode is providing the .orZero properties of such an optional as valid auto-completion options? I would've thought the generic constraints would prevent me from being able to see them.
For what it's worth, I'm using Xcode 10.1, and Swift 4.2
.orZero being provided as an auto-completion is a bug. It can be circumvented by rewriting your extensions in terms of the appropriate literal protocols.
public extension Optional where Wrapped: ExpressibleByIntegerLiteral {
var orZero: Wrapped { return self ?? 0 }
}
public extension Optional where Wrapped: ExpressibleByBooleanLiteral {
var orFalse: Wrapped { return self ?? false }
}
Expressed in this way, Swift can now figure out that .isZero ought not to be suggested for i.e. a variable of type String?, and if you try to call it anyway, it will give the error Type 'String' does not conform to protocol 'ExpressibleByIntegerLiteral'.
Take a look at this.
In you extension .orZero is only for Int, Float, Double.
For String you have .orEmpty.
I'd like to implement such property, that it's value is available for reading only one time, and then the property should be set to nil.
I've implemented it in such way:
private var _readOnce: String?
var readOnce: String? {
get {
let value = _readOnce
_readOnce = nil
return value
}
set {
_readOnce = newValue
}
}
readOnce = "Andrej"
print("read once = \(readOnce)") // prints read once = Optional("Andrej")\n"
print("read once = \(readOnce)") // prints read once = nil\n"
But I'feel like using a separate property _readOnce is not the "swifty" / "most elegant" way to do it.
Does anyone know of a different way, that wouldn't require to use a separate property?
I can confirm that the above code works, it's only that I feel it could be more elegant with less lines to achieve the same behaviour.
I don't know that there's a way to avoid having a backing property, but what I'd probably do is to make a helper type to wrap up the behavior. Something like this:
struct OneTimeValue<T>
{
private var isUnread = true
private let value : T
init(_ value: T)
{
self.value = value
}
func get() -> T?
{
guard isUnread else {
return nil
}
self.isUnread = false
return self.value
}
}
You could also write this a little differently if you prefer, by nilling out value inside of get(), for example, but the general plan holds.
Then your class becomes:
class Miser
{
var readOnce : String?
{
return self._readOnce.get()
}
private let _readOnce = OneTimeValue("Can't touch this (twice)")
}
I've also used this pattern for a UserDefaultsValue (storage to/from user defaults) and a SynchronizedValue (read-write lock on a property) and I think it works well.
As far as I know it is not possible without a second variable. This is because computed properties do not store any data for the variable they represent:
In addition to stored properties, classes, structures, and
enumerations can define computed properties, which do not actually
store a value.
For non-computed properties, the only observers you can have are based upon the setting of the variable, not the getting (i.e. willSet and didSet)
Hope that helps!
EDIT:
It can be done with closures and property observers if you're careful:
This requires no other variables (instead the value is captured by the closure), but it is rather unclear — I wouldn't recommend it.
var readOnce: () -> String? = {nil} {
didSet{
readOnce = { [weak self, readOnce] in
self?.readOnce = {nil}
return readOnce()
}
}
}
readOnce() // returns nil
readOnce = {"Hi"}
readOnce() // returns optional wrapped "Hi"
readOnce() // returns nil
A more 'Swifty' answer for you :D
After Swift 5.1, We can use Property Wrapper
#propertyWrapper
struct ReturnAndFree<T> {
private var value: T?
init(wrappedValue: T?) {
value = wrappedValue
}
var wrappedValue: T? {
mutating get {
defer { value = nil }
return value
}
set {
value = newValue
}
}
}
I have several properties like this in my Swift 3 code:
var dinActive: Bool {
get { return UserDefaults.standard.bool (forKey: "bo", fallback: true) }
set { UserDefaults.standard.set (newValue, forKey: "bo") }
}
var spdif1Active: Bool {
get { return UserDefaults.standard.bool (forKey: "spdif1", fallback: true) }
set { UserDefaults.standard.set (newValue, forKey: "spdif1") }
}
I wonder if I can make this more compact. E.g, I'd avoid repeating the string literal in both getter and setter functions, like with let s = "bo". Is that possible in some way?
Also, I wonder if I can make this repeated pattern into even shorter code, like I could do with classes and generics, or with a #define macro in C. Though, that's probably better asked in a separate question. If you have a suggestion for that and it's not answered on SO yet, just add a comment and I'll make a new question of it.
you can create a let constant outside of your class for it. For example:
//declaring constant outside of class
let SPDif1Key: String = "spdif1"
class YourClass
{
var dinActive: Bool {
get { return UserDefaults.standard.bool (forKey: SPDif1Key, fallback: true) }
set { UserDefaults.standard.set (newValue, forKey: SPDif1Key) }
}
}
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) {
...
}
}
In ObjC I used to call in my init something like
- init() {
[self initView1]
[self initView2]
}
to separate the setup of the views
but in swift I can't call a function before any variable has been set, is there something I'm missing or it's not possible ?
You can assign an initial value on their declaration line:
class MyClass {
var prop1: String = ""
var prop2: String = ""
init() {
self.initView1()
self.initView2()
}
func initView1() {
self.prop1 = "Hello"
}
func initView2() {
self.prop2 = "World"
}
}
Or alternatively, make them implicitly unwrapped optionals by adding an exclamation mark (!):
var prop1: String!
var prop2: String!
This tell the compiler that the programmer has guaranteed that these properties will be properly initialized before use.
In Swift, every property must be initialized before you can call methods.
This is described in detail in the chapter Two-Phase Initialization of the Swift Programming Language Manual.
If you want to delegate initialization to a method, then you at least have to provide some dummy values first.
Alternatively, you can refactor your code to create your views from static methods (if that is possible); then you can use these objects for initialization:
class MyClass {
let prop1: String
let prop2: String
static func create1() -> String {
return "Hello"
}
static func create2() -> String {
return "World"
}
init() {
prop1 = Blah.create1()
prop2 = Blah.create2()
}
}