What is the some keyword in Swift(UI)?
some View
is an opaque result type as introduced by SE-0244 and is available in Swift 5.1 with Xcode 11. You can think of this as being a "reverse" generic placeholder.
Unlike a regular generic placeholder which is satisfied by the caller:
protocol P {}
struct S1 : P {}
struct S2 : P {}
func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.
An opaque result type is an implicit generic placeholder satisfied by the implementation, so you can think of this:
func bar() -> some P {
return S1() // Implementation chooses S1 for the opaque result.
}
as looking like this:
func bar() -> <Output : P> Output {
return S1() // Implementation chooses Output == S1.
}
In fact, the eventual goal with this feature is to allow reverse generics in this more explicit form, which would also let you add constraints, e.g -> <T : Collection> T where T.Element == Int
. See this post for more info.
The main thing to take away from this is that a function returning some P
is one that returns a value of a specific single concrete type that conforms to P
. Attempting to return different conforming types within the function yields a compiler error:
// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
if x > 10 {
return S1()
} else {
return S2()
}
}
As the implicit generic placeholder cannot be satisfied by multiple types.
This is in contrast to a function returning P
, which can be used to represent both S1
and S2
because it represents an arbitrary P
conforming value:
func baz(_ x: Int) -> P {
if x > 10 {
return S1()
} else {
return S2()
}
}
Okay, so what benefits do opaque result types -> some P
have over protocol return types -> P
?
1. Opaque result types can be used with PATs
A major current limitation of protocols is that PATs (protocols with associated types) cannot be used as actual types. Although this is a restriction that will likely be lifted in a future version of the language, because opaque result types are effectively just generic placeholders, they can be used with PATs today.
This means you can do things like:
func giveMeACollection() -> some Collection {
return [1, 2, 3]
}
let collection = giveMeACollection()
print(collection.count) // 3
2. Opaque result types have identity
Because opaque result types enforce a single concrete type is returned, the compiler knows that two calls to the same function must return two values of the same type.
This means you can do things like:
// foo() -> <Output : Equatable> Output {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.
This is legal because the compiler knows that both x
and y
have the same concrete type. This is an important requirement for ==
, where both parameters of type Self
.
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
This means that it expects two values that are both the same type as the concrete conforming type. Even if Equatable
were usable as a type, you wouldn't be able to compare two arbitrary Equatable
conforming values with each other, for example:
func foo(_ x: Int) -> Equatable { // Assume this is legal.
if x > 10 {
return 0
} else {
return "hello world"
}
}
let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.
As the compiler cannot prove that two arbitrary Equatable
values have the same underlying concrete type.
In a similar manner, if we introduced another opaque type returning function:
// foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
// bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable {
return "" // The opaque result type is inferred to be String.
}
let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.
The example becomes illegal because although both foo
and bar
return some Equatable
, their "reverse" generic placeholders Output1
and Output2
could be satisfied by different types.
3. Opaque result types compose with generic placeholders
Unlike regular protocol-typed values, opaque result types compose well with regular generic placeholders, for example:
protocol P {
var i: Int { get }
}
struct S : P {
var i: Int
}
func makeP() -> some P { // Opaque result type inferred to be S.
return S(i: .random(in: 0 ..< 10))
}
func bar<T : P>(_ x: T, _ y: T) -> T {
return x.i < y.i ? x : y
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.
This wouldn't have worked if makeP
had just returned P
, as two P
values may have different underlying concrete types, for example:
struct T : P {
var i: Int
}
func makeP() -> P {
if .random() { // 50:50 chance of picking each branch.
return S(i: 0)
} else {
return T(i: 1)
}
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.
Why use an opaque result type over the concrete type?
At this point you may be thinking to yourself, why not just write the code as:
func makeP() -> S {
return S(i: 0)
}
Well, the use of an opaque result type allows you to make the type S
an implementation detail by exposing only the interface provided by P
, giving you flexibility of changing the concrete type later down the line without breaking any code that depends on the function.
For example, you could replace:
func makeP() -> some P {
return S(i: 0)
}
with:
func makeP() -> some P {
return T(i: 1)
}
without breaking any code that calls makeP()
.
See the Opaque Types section of the language guide and the Swift evolution proposal for further information on this feature.
what is the as keyword in swift
You use the as
keyword to cast data types. UIWindow rootViewController
is of type UIViewController
. You downcast it to UISplitViewController
.
Memory-related crash caused by the some keyword in Swift
Opaque types don't seem to be made for definitions like this. There's a lot of interesting information about this on this SO thread: What is the `some` keyword in Swift(UI)?
You can type the variable as AnyView
and use AnyView()
to wrap/type erase the content -- then you can use any modifiers you want.
let txt: AnyView = AnyView(Text("Hi").frame(width: 20, height: 20, alignment: .center))
I particularly like this extension to make it look a little cleaner:
extension View {
func eraseToAnyView() -> AnyView {
return AnyView(self)
}
}
let txt: AnyView = Text("Hi").frame(width: 20, height: 20, alignment: .center).eraseToAnyView()
What do these characters in Swift mean . If I wrapped a keyword In them, what would that mean exactly
It's a generic definition. Generics are useful when you’re writing code that could be applied to many different types.
For example, that means that UIHostingController could be initialised with any view.
hostingController = UIHostingController.init(rootView: ContentView())
struct ContentView: View {
var body: some View {
Text("some text")
}
}
Hope this is helpful!
What does the SwiftUI `@State` keyword do?
The @State
keyword is a @propertyWrapper
, a feature just recently introduced in Swift 5.1. As explained in the corresponding proposal, it's sort of a value wrapper avoiding boilerplate code.
Sidenote: @propertyWrapper
has previously been called @propertyDelegate
, but that has changed since. See this post for more information.
The official @State documentation has the following to say:
SwiftUI
manages the storage of any property you declare as a state.
When the state value changes, the view invalidates its appearance and
recomputes the body. Use the state as the single source of truth for a
given view.A State instance isn’t the value itself; it’s a means of
reading and mutating the value. To access a state’s underlying value,
use its value property.
So when you initialize a property that's marked @State
, you're not actually creating your own variable, but rather prompting SwiftUI
to create "something" in the background that stores what you set and monitors it from now on! Your @State var
just acts as a delegate to access this wrapper.
Every time your @State
variable is written, SwiftUI
will know as it is monitoring it. It will also know whether the @State
variable was read from the View
's body
. Using this information, it will be able to recompute any View
having referenced a @State
variable in its body
after a change to this variable.
How to return variable defined in Task in Swift
Well, it would be useful to know how newArtist
is used, but I believe you will need to make it async as well.
func newArtist(name: String, notes: String, artwork: NSImage?) async -> Artist {
let artist = Artist(name: name, notes: notes, artwork: artwork)
await insertToArtists(artist: artist)
return artist
}
And then use Task
where you are calling newArtist
func whereYouUseNewArtist() {
//YourCode
Task {
//YourCode
x = await newArtist(name: name, notes: notes, artwork: artwork)
//YourCode
}
//YourCode
}
If you need to update your UI with the result of newArtist
, remember to do it in the main thread. You can do it by adding @MainActor
to where you use it. Example:
let artistToShowOnUI: Artist
@MainActor func whereYouUseNewArtist() {
Task {
artistToShowOnUI = await newArtist(name: name, notes: notes, artwork: artwork)
}
}
Related Topics
Swift 3 Incorrect String Interpolation With Implicitly Unwrapped Optionals
Swift 5.0: 'Withunsafebytes' Is Deprecated: Use 'Withunsafebytes≪R≫(...)
Using Decodable in Swift 4 With Inheritance
How to Reset the App Between Tests in Swift Xctest Ui
Swift: How to Add a Protocol Extension to a Protocol
How to Check If a Text Field Is Empty or Not in Swift
Any Reason Not Use Use a Singleton "Variable" in Swift
How to Convert Data to Hex String in Swift
Alamofire Get API Request Not Working as Expected
Append Text or Data to Text File in Swift
Flatten an Array of Arrays in Swift
How to Unwrap an Optional Value from Any Type
Swift 2 ( Executefetchrequest ): Error Handling
Swipe-Able Table View Cell in iOS 9
Number of Words in a Swift String For Word Count Calculation