Propagate an optional through a function (or Init) in Swift
You can simply use Optional
's map(_:)
method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return nil
.
let f : Float? = 2
// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
This is because map(_:)
expects a transformation function of type (Float) -> Double
in this case, and Double
's float initialiser is such a function.
If the transform also returns an optional (such as when converting an String
to a Int
), you can use flatMap(_:)
, which simply propagates a nil
transform result back to the caller:
let s : String? = "3"
// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }
Can I check if an optional is nil by using it as an argument?
You can use the
public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
method of Optional
:
if let parsedZoomURL = zoomURL.flatMap( { URL(string: $0) }) {
//do stuff
}
or shorter (as someone noticed in a now deleted comment):
if let parsedZoomURL = zoomURL.flatMap(URL.init) {
//do stuff
}
The optional binding succeeds only if zoomURL
is not nil
and the closure (which is then called with the unwrapped value
of zoomURL
) does not return nil
.
Is there a neater alternative to if-let to call a function on an Optional?
You can use map or flatMap on Optional types. flatMap basically evaluates the closure passed to it if and only if the value exist.
Here is a sample,
let maybeValue: String? = "awesome swift"
let val = maybeValue.flatMap { $0.uppercased() }
Why isn't a implicit optional required in a class's init method?
An implicit optional is still an optional, so it can be nil
and it does not need to be set at the time of initialisation. You will, however, get still get an exception if you access it unconditionally when it is nil.
If your Phone
class were:
class Phone {
let model: String
var owner: User!
init(model: String) {
self.model = model
print("Phone \(model) is initialized")
}
deinit {
print("Phone \(model) is being deallocated")
}
}
and you said
var aPhone = Phone(model:"iPhone7")
let ownerName = aPhone.owner.name
Then you would get an exception on the second line because the implicitly unwrapped optional is nil
. That line is the equivalent of writing let ownerName = aPhone.owner!.name
if owner
were of type User?
.
Implicitly unwrapped optionals are very useful where a value cannot be assigned at initialisation, but a value will be assigned shortly thereafter, as it avoids the need to continually unwrap the variable.
For example, implicitly unwrapped optionals are often used for @IBOutlet
properties in a view controller. The property will be set by the storyboard load process, but after the view controller object is initialised. Since you know that the property will have a value by the time any of your code runs, the use of an implicitly unwrapped optional is safe and you avoid having to continually unwrap the property.
Your sample Phone
class is not a good use of implicitly unwrapped optionals; either a simple optional (as you have shown) or a required initialiser argument is appropriate depending on whether phones can be unowned or not.
Concatenate literal with Optional String
You can use the map
method of Optional
:
let username = name.map { "@" + $0 }
If name
is nil
then the closure is not executed and the result is nil
. Otherwise the closure is evaluated with $0
set to the unwrapped name.
Swift why unwrapping optional by guarding against NIL is not working
The type of s
is still Optional
, so whether you did a nil
check or not is irrelevant. The nil
check is done in runtime, while the type system is doing a compile-time check. The only way to ensure s
can never be nil
is via optional binding if let
or guard let
.
Swift how to create and test an object with nil properties?
You can make the init parameter an optional String?
, with a default
value nil
:
class Contact {
var displayName: String?
init(displayName: String? = nil) {
self.displayName = displayName
}
}
let contact1 = Contact()
let contact2 = Contact(displayName: "John")
The same works for the Contacts
class:
class Contacts {
func create(displayName: String? = nil) -> Contact {
return Contact(displayName: displayName)
}
}
let contacts = Contacts()
let contact3 = contacts.create()
let contact4 = contacts.create("Mary")
How do you create a SwiftUI view that takes an optional secondary View argument?
November 2021 update (Works in Xcode 11.x, 12.x, and 13.x)
After some thought and a bit of trial and error, I figured it out. It seems a bit obvious in hindsight.
struct SomeCustomView<Content>: View where Content: View {
let title: String
let content: Content
init(title: String, @ViewBuilder content: @escaping () -> Content) {
self.title = title
self.content = content()
}
// returns a new View that includes the View defined in 'body'
func sideContent<SideContent: View>(@ViewBuilder side: @escaping () -> SideContent) -> some View {
HStack {
self // self is SomeCustomView
side()
}
}
var body: some View {
VStack {
Text(title)
content
}
}
}
It works with or without the method call.
SomeCustomView(title: "string argument") {
// some view
}
SomeCustomView(title: "hello") {
// some view
}.sideContent {
// another view
}
Previous code with subtle bug: body
should be self
func sideContent<SideContent: View>(@ViewBuilder side: @escaping () -> SideContent) -> some View {
HStack {
body // <--- subtle bug, updates to the main View are not propagated
side()
}
}
Thank you Jordan Smith for pointing this out a long time ago.
Related Topics
Spritekit Physics in Swift - Ball Slides Against Wall Instead of Reflecting
Should Conditional Compilation Be Used to Cope With Difference in Cgfloat on Different Architectures
Swift: Print Decimal Precision of Division
Swift Generics: Requiring Addition and Multiplication Abilities of a Type
How to Create a View-Based Nstableview Purely in Code
Split Now Complains About Missing "Isseparator"
Trying to Know When a Window Closes in a MACos Document Based Application
How to Set the Legacy Swift Versions for Each Pod in Podfile
What Is '@_Silgen_Name' in Swift Language
The "Prefs" Url Scheme Is Not Working in iOS 10 (Beta 1 & 2)
Swift: How to Detect Linear Type Barcodes
How to Load an Image from Documents Directory on MACos Swift
Access Input from Uialertcontroller
How to Convert Timeinterval into Minutes, Seconds and Milliseconds in Swift
Using Function Parameter Names in Swift
Check Whether Swift Object Is an Instance of a Given Metatype