Swift struct initialization, making another struct like String
This is (in my opinion) neat part of the language. Yes, this is possible, thanks to the ExpressibleByStringLiteral
protocol.
Unfortunately, there is some complexity to it. ExpressibleByStringLiteral
inherits from ExpressibleByExtendedGraphemeClusterLiteral
, which itself inherits from ExpressibleByUnicodeScalarLiteral
. Thus, to conform to the first, you must conform to the other 2 above it.
This makes it possible for your struct or class to be initialized from:
- A
UnicodeScalarLiteralType
(such as aUnicodeScalar
, which is a single Unicode code point, e.g."A"
) - An
ExtendedGraphemeClusterLiteralType
(such as aCharacter
, which is a collection ofUnicodeScalar
s, such as"/code>)
- A
StringLiteralType
(such asString
, which is a collection ofCharacters
, such as"This is a string"
)
Here's an example implementation that just sets a String
member variable:
struct StringV2: ExpressibleByStringLiteral {
let s: String
init(unicodeScalarLiteral: UnicodeScalar) {
s = String(unicodeScalarLiteral)
}
init(extendedGraphemeClusterLiteral: Character) {
s = String(extendedGraphemeClusterLiteral)
}
init(stringLiteral: String) {
s = stringLiteral
}
}
let s1: StringV2 = "This is a string" // String
print(s1.s)
let s2: StringV2 = "A" // Unicode scalar
print(s2.s)
let s3: StringV2 = " // Extended grapheme cluster
print(s3.s)
How can I initialize a struct or class in Swift?
The anonymous closure is an unnamed function. It's useful whenever you want to initialize something with the result of calling a function, but you don't want to write a function like:
func makeDan() -> Person {
...
}
let person = makeDan()
That would mean you have to come up with a name for the function and find some place to put it, which means it's also visible and can be called by other pieces of code that don't need anything to do with makeDan. It's often useful to have functions that have no names.
Needing a function to initialise something is useful when you have something complex that needs some kind of computation, so multiple lines of stuff. It's also useful when the initialization is only wanted to be done if/when required:
lazy var dan: Person = { ... }()
Perhaps because the computation is expensive in some kind of resource use, like cpu or memory. Or possibly because the computation involves some kind of side effect, like opening a database or something, that's only wanted if/when the property is used.
Swift setting a struct value within another struct init
The problem is that none of your lines are actually accessing instances of your Cell
struct.
Here's a functioning adaptation of your code. I allowed myself to remove extra stuff that seem to have been left out from your codebase:
struct Cell {
var position: (Int,Int)
init(_ position: (Int,Int)) {
self.position = (0,0)
}
}
func positions(rows: Int, cols: Int) -> [(Int, Int)] {
return (0 ..< rows)
.map { zip( [Int](repeating: $0, count: cols) , 0 ..< cols ) }
.flatMap { $0 }
.map { ($0.0, $0.1) }
}
struct Grid {
var rows: Int = 10
var cols: Int = 10
var cells: [[Cell]] = [[Cell]]()
init(_ rows: Int, _ cols: Int) {
self.rows = rows
self.cols = cols
self.cells = Array.init(repeating: Array.init(repeating: Cell((0,0)), count: cols), count: cols)
positions(rows: rows, cols: cols).forEach { row, col in
cells[row][col].position = (row, col)
}
}
}
let g = Grid(1, 2)
print(g.cells[0][1].position)
Now, for a more detailed explanation of the errors you encountered:
var position = cells(position: (row, col))
Here you're not setting anything on any cell. Instead, you're trying to call your grid as if it was a function, with a parameter position: (Int, Int)
.
cells.position = (row, col)
Here you're trying to set a property position
on your matrix ([[Cell]]
). And obviously, Swift complains that such property does not exists in its builtin type Array
.
cells.position(row, col)
Here you're trying to set a property position
on your matrix ([[Cell]]
) and call it as a function with two parameters Int
. The problem is similar as above.
position *= cells.position(row, col)
Here I'm can't tell what's going on, since position
does not seems to have been declared in your code. I guess it comes from elsewhere in your codebase, or maybe it's merely a typo.
Setting type of generic struct during initialization (Swift)
All you have to do is to tell the compiler that T is a String
init(fromString: String, separator: String) where T == String {
// ...
}
How to automatically create an initializer for a Swift class?
Update As of Xcode 11.4
You can refactor
(right-click mouse menu) to generate the memberwise initializer
for class
and struct
.
Note that struct
automatic initializers are internal. You may want to generate memberwise initializer
when defining a module to make it public
.
Right-click > Refactor > 'Generate Memberwise Initializer'
For older Xcode
There are handy plugins:
https://github.com/rjoudrey/swift-init-generator https://github.com/Bouke/SwiftInitializerGenerator
Related Topics
Declaring and Using Custom Attributes in Swift
How to Open a Screen Directly in Xcuitest
Realitykit - How to Set a Modelentity's Transparency
Xcode 11 Beta 3, Build Error "Unknown Attribute 'State'", "Use of Undeclared Type 'View'" etc
How to Set Exit Code Value for a Command Line Utility in Swift
Playing a Sound in a Swift Playground
Instance Member Cannot Be Used on Type Class
Play Local Audio File with Avaudioplayer
Why Is Generic Specialization Lost Inside a Generic Function
Pickers Are Overlapping in iOS 15 Preventing Some of Them to Be Scrolled
Converting Swift 2.3 to Swift 3.0 - Error, Cannot Invoke 'Datatask' with an Argument List of Type'
Nsurlerrordomain with Code=-1100
Swift Struct Initialization, Making Another Struct Like String
Store Encodables in a Swift Dictionary
Why Is an Object Not Being Decoded
Swift 3 Optional Trouble. Can't Unwrap Url with Passed in String