What does {{{…}}} mean in Swift? - swift

I wrote the following code in playground.
struct Product {
var randomNumber: Int?
init?(number: Int){
if number <3 {return nil}
randomNumber=number
}
}
var mug = Product(number: 5) // {{{…}}}
In the output on the right I get {{{…}}} as indicated by the comment. What do this symbols mean?

It's a shorthand notation that indicates different levels of wrapping. Xcode is just telling you what's in the variable mug The outermost curly-brackets are the wrapping around the optional. The second level of brackets wraps around your struct properties and the third level of wrapping is an optional wrapped around your randomNumber property. You can visualize it by doing this.
var mug = Product(number: 5) // {{{...}}}
var amug = mug! // {{Some 5}}
var bmug = mug!.randomNumber // {Some 5}
var cmug = mug!.randomNumber! // 5

{...} means you are getting an optional result from Product containing another optional randomNumber . You can use "if let" to safely unwrap your optionals as follow:
if let mug = Product(number: 5) {
if let mugRandomNumber = mug.randomNumber {
println(mugRandomNumber) // 5
}
}

Related

how to understand some functions of this code [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
below are the code. About the button part. Why the if let is needed?
import SwiftUI
struct descView: View {
#ObservedObject var data: Activities
var activity: ActivityItem
var body: some View {
List {
Section {
VStack(alignment: .leading){
Text(activity.desc)
}
}
Section {
Text("How many times completed")
Text("\(activity.amount)")
Button("Make complete once") {
var newActivity = activity
newActivity.amount += 1
if let index = data.activities.firstIndex(of: activity) {
//The firstIndex(of:) method tells you the index of an element in an array if it exists, or returns nil otherwise.
data.activities[index] = newActivity
}
}
}
}
.navigationTitle(activity.name)
}
}
I'm a new beginner of swift.Cannot figure out what is the function of below part of code.Could someone explain it? thanks!
if let index = data.activities.firstIndex(of: activity) {
//The firstIndex(of:) method tells you the index of an element in an array if it exists, or returns nil otherwise.
data.activities[index] = newActivity
To make sure index isn't nil and/or optional value.
firstIndex returns nil if the activity isn't in data.activities
activities[index] // does not work if `index` is optional.
You can do this several different ways such as using guard but the goal is the same when you reach the line that uses index make sure it is not nil.
Per your comment right now the Button is making a copy of the activity, changing the copy, and then replacing the list's activity with the updated one.
This is needed because var activity: ActivityItem is immutable (cannot change). If you add #Binding to the activity and make the connection with the list's object in the parent view you can skip this step and alter it directly.
https://developer.apple.com/wwdc21/10018
Shows a sample around minute 8
and it would look something like this in your code
List($data.activities) { $activity in
descView(activity: $activity)
}
In Swift, variables can be optional and non-optional. When a variable is optional, this means it can be nil. If it's non-optional, it is not allowed to be nil. To set a variable's type to optional, you add a ? to the end of the type (e.g. String?).
For example:
var nonOptionalInt: Int = 5
var optionalInt: Int? = 5
optionalInt = nil // Works fine
nonOptionalInt = nil // This will result in an error (and crash)
Sometimes, you want to check if an optional variable is nil or not before you proceed. In your case, you want to make sure index is not nil. You want to "unwrap" the optional index (Int?) to become a non-optional index (Int).
By using if let you are unwrapping the variable (via a process called optional binding) and if it's not nil, you can use it. If it is nil you will skip the if block and the code inside will not be executed.
A full example:
import Foundation
let optionalInt: Int? = 5
print(type(of: optionalInt)) // Prints Optional<Int> - At this moment, the content of the optionalInt variable MIGHT be nil
if let unwrappedInt = optionalInt { // If optionalInt is NOT nil, this statement will be true and I enter the if-block
print(unwrappedInt) // Prints 5 - Now I know for sure that unwrappedInt is not nil
print(type(of: unwrappedInt)) // Prints Int - Not optional anymore
}
let anotherOptionalInt: Int? = nil
if let unwrappedInt = anotherOptionalInt { // If optionalInt is NOT nil, this statement will be true and I enter the if-block
print(unwrappedInt) // This won't be printed
} else {
print("anotherOptionalInt was nil!") // This will print
}
Please note that you can just use the same variable name if let optionalInt = optionalInt { .. }, and the optionalInt inside the if-block's scope will be a non-optional Int. The optionalInt outside the if-block will remain the optional Int?.
Check this page more information on Optionals in Swift.

How to initialize a struct with dictionaries in Swift

I want to initialize every time a struct with dictionaries. Later, I'm going to use its properties instead a dictionary's keys and values - it seems rather easier. However, when I try the code below, it tells me that "Return from initializer without initializing all stored properties" and "1. 'self.one' not initialized" and "2. 'self.two' not initialized". My question is how to initialize a struct from a dictionary, so that I have basically a struct with the contents of the dictionary? Or how to transform it into struct?
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
one = ""
two = []
for i in three {
self.one = i.key
self.two = i.value
}
} ERROR! - Return from initializer without initializing all stored properties
}
for in clause may have zero runs, in which case struct properties will not be initialized. You have to provide default values (or emit fatalError if you really need to).
While I think your example is pure synthetical, there is no need to loop through array, you can set properties to its last entry.
The issues is that if three is an empty Dictionary, the instance properties one and two don't get initialised. Also, you are overwriting the properties in each iteration of the for loop and the compiler cannot guarantee that there will be any iterations of the loop in compile-time, hence the compiler error.
You could make the initialiser failable to account for this by checking that the dictionary actually contains at least one key-value pair and assigning that first key-value pair to your properties.
struct Blabla {
var one: String
var two: [Int]
init?(three: [String: [Int]]) {
guard let key = three.keys.first, let value = three[key] else { return nil }
one = key
two = value
}
}
However, you should rethink what it is that you are actually trying to achieve, since with your current setup you have a mismatch between your init input values and the properties of your struct.
This code should compile, but it feels unsafe to me to initialize a Struct in this way because:
It assume your dictionary has values in it.
Your stored properties will always have the last value you looped through.
In order to pull values out to satisfy the compiler you need to force unwrap them. (With Dávid Pásztor's guard-letting approach, this can be avoided)
struct Blabla {
var one: String
var two: [Int]
init(three: [String: [Int]]) {
self.one = three.keys.first!
self.two = three[three.keys.first!]!
}
}
let input = ["pizza": [1,2]]
let l = Blabla(three: input)
If I were you I would let the memberwise initializer that you get for free do its thing and provide either a specialized initializer to handle your case of taking a Dictionary as input or move that parsing to another function/class/etc....
The compiler error is clear: If the dictionary is empty the struct members are never initialized. But the code makes no sense anyway as each iteration of the dictionary overwrites the values.
Maybe you mean to map the dictionary to an array of the struct
struct Blabla {
let one: String
let two: [Int]
}
let three = ["A":[1,2], "B":[3,4]]
let blabla = three.map{Blabla(one: $0.key, two: $0.value)}
print(blabla) // [Blabla(one: "A", two: [1, 2]), Blabla(one: "B", two: [3, 4])]
struct blabla{
var a : string
var b : [int] = []
init(_ data: [string:[int]]){
// whatever you want to do
}
}

What are some good ways to avoid repeating array index accessing operation on same Array of struct element?

Consider the following code:
struct Card {
var name0: String
var name1: String
}
var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))
// Need to perform array index access,
// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"
// ...
// ...
// "good bye"
print(cards[0].name0 + " " + cards[0].name1)
Instead of having to perform multiple array index accessing every time I want to mutate a property in struct, is there a technique to avoid such repeating array index accessing operation?
// Ok. This is an invalid Swift statement.
var referenceToCardStruct = &(cards[0])
referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"
// ...
// ...
There are a lot of good answers here, and you should not think of value types as "a limitation." The behavior of value types is very intentional and is an important feature. Generally, I'd recommend inout for this problem, like matt suggests.
But it is also certainly possible to get the syntax you're describing. You just need a computed variable (which can be a local variable).
let index = 0 // Just to show it can be externally configurable
var referenceToCardStruct: Card {
get { cards[index] }
set { cards[index] = newValue }
}
referenceToCardStruct.name0 = "good"
referenceToCardStruct.name1 = "bye"
print(cards[0].name0 + " " + cards[0].name1)
struct Card {
var name0: String
var name1: String
}
var cards = [Card]()
// every time I want to mutate a struct property :(
cards[0].name0 = "good"
cards[0].name1 = "bye"
Instead of having to perform multiple array index accessing every time I want to mutate a property in struct, is there a technique to avoid such repeating array index accessing operation?
No. When you have an array of struct, then in order to make a change to a struct within the array, you must refer to that struct by index.
If you don't want to see the repeated use of the index, you can hide it in a function using inout:
func mutate(card: inout Card) {
card.name0 = "good"
card.name1 = "bye"
}
for index in cards.indices {
mutate(card:&cards[index])
}
Some day, Swift may include for inout which will allow you to cycle through an array of struct and mutate each struct instance directly. But that day is not yet here.
In answer to the implied question whether it is worth switching to a class just to avoid this repeated use of the index, my answer would be No. There is a good reason for using structs — they are much easier to reason about than classes, and are one of Swift's best features — and I would keep using them if that reason matters to you.
struct is a value type you can't get a reference to it's object with assignment , you should go that way , use a mutating method like https://stackoverflow.com/a/52497495/5820010 or use a class instead
If you don't want to repeat the index, then create a variable from the value you want.
var cards = [Card]()
cards.append(Card(name0: "hello", name1: "world"))
var card = cards[0]
card.name0 = "good"
card.name1 = "bye"
// ...
// ...
cards[0] = card // update the array with the updated card
// "good bye"
print(card.name0 + " " + card.name1)
I think the mutating method is the way to go, as Sh_Khan points out.
In your case, I would do something like:
1> struct Card {
2. var name0: String
3. var name1: String
4. }
5.
6. var cards = [Card]()
7. cards.append(Card(name0: "hello", name1: "world"))
cards: [Card] = 1 value {
[0] = {
name0 = "hello"
name1 = "world"
}
}
8> extension Card {
9. mutating func setNames(name0: String, name1: String) {
10. self.name0 = name0
11. self.name1 = name1
12. }
13. }
14> cards[0].setNames(name0: "x", name1: "y")
15> cards
$R0: [Card] = 1 value {
[0] = {
name0 = "x"
name1 = "y"
}
}
Another approach is a wholesale update of cards[0].
Kind of makes you wish for record updating syntax (a la Haskell or Elm) or dictionary merging-type functionality. But look on the bright side. Maybe Swift's lack of making this easy is testament to the fact that it has static-typing-and-value-semantics-while-allowing-mutation and that combination of features, I think, makes the mutating func or full array element update all but required. I'm not sure Swift has a syntactic feature for updating multiple properties in one shot (without writing your own function or method).

Nil-Coalescing Operator without changing value [duplicate]

This question already has answers here:
Perform assignment only if right side is not nil
(7 answers)
Closed 5 years ago.
Nil-Coalescing Operators are one of my favorite things about Swift. Since becoming quite familiar with Swift, I've run into a few different special cases. One is where I want to assign an Optional value to a variable if it exists, otherwise, do nothing. I currently see two ways of doing this:
var a : String?
var b : String?
// Possibly assign a non-nil value to a and/or b
/* First Way */
a = b ?? a
/* Second Way */
if let b = b {
a = b
}
In this context, it seems like the first way is probably fine, but when variables get much longer names like mapViewController.destinationCardTitle, the first way can get pretty long. I also can't just assign the value of a to nil or an empty String because if it already contains a non-nil value and b = nil, I don't want to change the value of a.
I'm wondering if there is a way to basically do the following without writing a twice.
a = b ?? a
You can design your own infix operator:
infix operator ?=
func ?=<T>(lhs: inout T, rhs: T?) {
lhs = rhs ?? lhs
}
var a = "a"
var b: String? = "b"
a ?= b
print(a) // "b\n"
Since your concern is with long variable names, let's look at your possibilities with long variable names:
nil-coalescing:
aLongVariableName = bCrazyLongVariableName ?? aLongVariableName
if-let:
if let x = bCrazyLongVariableName {
aLongVariableName = x
}
if-nil:
if bCrazyLongVariableName != nil {
aLongVariableName = bCrazyLongVariableName
}
Of those three possible options, if let is the shortest amount of code since each long variable name is only shown once. But you have the overhead of if let x = and the curly braces. So you need to have variable names that are long enough to counter that extra syntax.
Personally, readability is more important than length. And copy and paste means far less typing. For this reason, using ?? is the much better solution. Its intent is clearer.
You asked about a way to avoid the 2nd a using ??. You can't. There is no other syntax that provides the real shortcut you are looking for.
You could write a function that takes a as an inout parameter and b as a normal parameter.
func x(_ a: inout String?, _ b: String?) {
if b != nil {
a = b
}
}
var a = String?
var b = String?
x(&a, b)
It sure is interesting - and this is when you have a golden opportunity to make the most out of Swift. Use the big hammer on this one:
var a: String?
var b: String?
func attempt_To_Set_A_New_Value_To_A(using b: Any?) -> String {
if b != nil {
guard b is String else {
// OH no! It's not a string!!!
return ""
}
// Just to make sure..
if let bString = b as? String {
return bString
}
}
// WARNING - b is definitely nil!
return ""
}
a = attempt_To_Set_A_New_Value_To_A(using b: b).isEmpty() ? a : attempt_To_Set_A_New_Value_To_A(using b: b)
If you want to have less fun, or you're simply having a bad day, I'd probably write it as such:
if b != nil { a = b }

How to solve "String interpolation produces a debug description for an optional value; did you mean to make this explicit?" in Xcode 8.3 beta?

Since beta 8.3, zillions warnings "String interpolation produces a debug description for an optional value; did you mean to make this explicit?" appeared in my code.
For example, the warning popped in the following situation up, where options could lead to nil:
let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"
As previously designed, it was ok for me (and the compiler) the optionals to be interpolated as 'nil'. But compiler changed its mind.
What the compiler suggests is to add a String constructor with description as follows:
let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"
Obviously, the results is explicit but also very very cumbersome in my opinion. Is there a better option? Do I have to fix all those warning or better wait for the next beta?
This is a change that was made in this pull request due to the fact that interpolating Optional(...) into the resultant string is often undesirable, and can be especially surprising in cases with implicitly unwrapped optionals. You can see the full discussion of this change on the mailing list here.
As mentioned in the pull request discussion (although unfortunately not by Xcode) – one slightly nicer way to silence the warning than the use of String(describing:) is to add a cast to the optional type of whatever you're interpolating, so for example:
var i: Int? = 5
var d: Double? = nil
print("description of i: \(i as Int?)") // description of i: Optional(5)
print("description of d: \(d as Double?)") // description of d: nil
Which can also be generalised to as Optional:
print("description of i: \(i as Optional)") // description of i: Optional(5)
print("description of d: \(d as Optional)") // description of d: nil
In Swift 5, with the new string interpolation system introduced by SE-0228, another option is to add a custom appendInterpolation overload for DefaultStringInterpolation:
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(optional: T?) {
appendInterpolation(String(describing: optional))
}
}
var i: Int? = 5
var d: Double? = nil
print("description of i: \(optional: i)") // description of i: Optional(5)
print("description of d: \(optional: d)") // description of d: nil
And, if desired, you could even remove the argument label to disable the warning entirely within a module (or within a particular file if you mark it as fileprivate):
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(_ optional: T?) {
appendInterpolation(String(describing: optional))
}
}
var i: Int? = 5
var d: Double? = nil
print("description of i: \(i)") // description of i: Optional(5)
print("description of d: \(d)") // description of d: nil
Though personally I would prefer to keep the argument label.
Two easier ways of dealing with this issue.
Option 1:
The first would be by "force-unwrapping" the value you would like to return using a bang (!)
var someValue: Int? = 5
print(someValue!)
Output:
5
Option 2:
The other way, which could be the better way - is to "safely-unwrap" the value you want returned.
var someValue: Int? = 5
if let newValue = someValue {
print(newValue)
}
Output:
5
Would recommend to go with option 2.
Tip: Avoid force unwrapping (!) where possible as we are not sure if we will always have the value to be unwrapped.
seems using String(describing:optional) is simplest.
default value ?? makes no sense for non-Strings e.g Int.
If Int is nil then you want the log to show 'nil' not default to another Int e.g. 0.
Some playground code to test:
var optionalString : String? = nil
var optionalInt : Int? = nil
var description_ = ""
description_ = description_ + "optionalString: \(String(describing: optionalString))\r"
description_ = description_ + " optionalInt: \(String(describing: optionalInt))\r"
print(description_)
Output
optionalString: nil
optionalInt: nil
After updating to Xcode 8.3 and getting a lot of warning messages, I came up with the following that is more like the original output behavior, easy to add in, reduces the verboseness of using "String(describing:)" both in code and output.
Basically, add an Optional extension that gives a String describing the thing in the optional, or simply "nil" if not set. In addition, if the thing in the optional is a String, put it in quotes.
extension Optional {
var orNil : String {
if self == nil {
return "nil"
}
if "\(Wrapped.self)" == "String" {
return "\"\(self!)\""
}
return "\(self!)"
}
}
And usage in a playground:
var s : String?
var i : Int?
var d : Double?
var mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = nil i = nil d = nil"
d = 3
i = 5
s = ""
mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = "" i = 5 d = 3.0"
s = "Test"
d = nil
mixed = "s = \(s.orNil) i = \(i.orNil) d = \(d.orNil)" // "s = "Test" i = 5 d = nil"
Thanks for help from following link:
check-if-variable-is-an-optional-and-what-type-it-wraps
See Ole Begeman's fix for this. I love it. It creates a ??? operator which you can then use like this:
var someValue: Int? = 5
print("The value is \(someValue ??? "unknown")")
// → "The value is 5"
someValue = nil
print("The value is \(someValue ??? "unknown")")
// → "The value is unknown"
Double click on the yellow triangle displayed on line containing this warning. This will show FixIt with two solutions.
Use String(describing:) to silence this warning :
Using this it will become String(describing:<Variable>)
Eg. : String(describing: employeeName)
Provide a default value to avoid this warning :
Using this it will become (<Variable> ?? default value)
Eg.: employeeName ?? “Anonymous” as! String
Swift 5
My solution is making an extension which unwrap Optional object to Any.
When you log the object or print it out, you can see the actual object or <nil>⭕️ (combination from text and visual character). It's useful to look at, especially in the console log.
extension Optional {
var logable: Any {
switch self {
case .none:
return "<nil>|⭕️"
case let .some(value):
return value
}
}
}
// sample
var x: Int?
print("Logging optional without warning: \(x.logable)")
// → Logging optional without warning: <nil>|⭕️
Create an interpolation method that accepts an optional generic Type with an unnamed parameter. All your annoying warnings will magically disappear.
extension DefaultStringInterpolation {
mutating func appendInterpolation<T>(_ optional: T?) {
appendInterpolation(String(describing: optional))
}
}