owned this note
owned this note
Published
Linked with GitHub
---
title: Swift extensions
description: Lateinit and scope fuction in Swift
tags: Swift
type: slide
slideOptions:
transition: 'fade'
---
## Swift extensions
#### Allen @ PhotoGrid
---
## Lateinit
#### The lateinit lets you defer property initialization. When using lateinit, you should initialize your property as soon as possible.
----
### Swift
```swift=
class LoginViewController: UIViewController {
//Class 'LoginViewController' has no initializers
private var loginButton: UIButton
override func viewDidLoad() {
super.viewDidLoad()
loginButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 36))
view.addSubview(loginButton)
}
}
```
----
### Kotlin
```kotlin=
class LoginFragment : Fragment() {
private lateinit var loginButton: Button
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loginButton = view.findViewById(R.id.login_button)
}
}
```
----
### Swift
```swift=
class LoginViewController: UIViewController {
@Lateinit private var loginButton: UIButton
override func viewDidLoad() {
super.viewDidLoad()
loginButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 36))
view.addSubview(loginButton)
}
}
```
----
#### Implemente lateinit in Swift
```swift=
@propertyWrapper
struct Lateinit<T> {
private var _value: T?
var wrappedValue: T {
get {
guard let value = _value else {
fatalError("Lateinit property has not been initialized")
}
return value
}
set { _value = newValue }
}
}
```
---
## Scope function
#### Scope functions' sole purpose is to execute a block of code within the context of an object.
----
#### Duplicate coding
```swift=
acceptButton.setBackgroundColor(SplashGDPRColors.acceptButton.value, for: .normal)
acceptButton.setTitleColor(.white, for: .normal)
acceptButton.setTitle(String(PG_gdprContinue), for: .normal)
acceptButton.clipsToBounds = true
acceptButton.layer.cornerRadius = 3
acceptButton.isEnabled = true
```
```swift=
withObject(acceptButton) {
$0.setBackgroundColor(SplashGDPRColors.acceptButton.value, for: .normal)
$0.setTitleColor(.white, for: .normal)
$0.setTitle(String(PG_gdprContinue), for: .normal)
$0.clipsToBounds = true
$0.layer.cornerRadius = 3
$0.isEnabled = true
}
```
----
#### Redundant variable and statement
```swift=
let row = itemArray.firstIndex {
$0.type == .tool
}
if let row = row {
let indexPath = IndexPath(row: row, section: 0)
if let toolCell = tableView.cellForRow(at: indexPath) as? MainPageToolCell {
toolCell.refreshDraftsEntrance()
}
}
```
```swift=
itemArray.firstIndex {
$0.type == .tool
}?.let { //$0: Int
IndexPath(row: $0, section: 0)
}.let { //$0: IndexPath
tableView.cellForRow(at: $0) as? MainPageToolCell
}?.also { //$0: MainPageToolCell
$0.refreshDraftsEntrance()
}
```
----
### Functional programming!
----
### Kotlin
#### The Kotlin standard library contains several functions:
#### let, run, with, apply, and also
----
### Kotlin
<style>
.heatMap th {
background: gray;
}
.heatMap tr:nth-child(1) { background: orange; }
.heatMap tr:nth-child(2) { background: orange; }
.heatMap tr:nth-child(3) { background: green; }
.heatMap tr:nth-child(4) { background: blue; }
.heatMap tr:nth-child(5) { background: blue; }
</style>
<div class="heatMap">
<font size=5>
| Function | Object reference | Return value | Is extension function |
|:-------- |:---------------- |:-------------- |:--------------------- |
| let | it | Lambda result | YES |
| run | this | Lambda result | YES |
| with | this | Lambda result | NO |
| apply | this | Context object | YES |
| also | it | Context object | YES |
</font>
</div>
----
### Kotlin
#### Context object: this or it
```kotlin=
val str = "Hello"
// this
str.run {
println("The string's length: $length")
//println("The string's length: ${this.length}") // does the same
}
// it
str.let {
println("The string's length is ${it.length}")
}
```
---
### Kotlin
#### run & let
```kotlin=
//run
val price = Book().run {
name = "Scope Functions"
price = 400
price
}
```
```kotlin=
//let
val price = Book().let {
it.name = "Scope Functions"
it.price = 400
it.price
}
```
----
### Kotlin
#### with
```kotlin=
//with
val book = Book()
val privce = with(book) {
name = "Scope Functions"
price = 400
price
}
```
----
### Kotlin
#### also & apply
```kotlin=
//apply
val book = Book().apply {
name = "Scope Functions"
price = 400
}
//also
val book = Book().also {
it.name = "Scope Functions"
it.price = 400
}
```
----
### Swift
#### Can the context be changed in Swift?
----
### Swift
#### let & also
```swift=
//let
let price: Int = Book().let {
$0.name = "Scope Functions"
$0.price = 400
$0.price
}
```
```swift=
//also
let bool = Book().also {
$0.name = "Scope Functions"
$0.price = 400
}
```
----
### Swift
#### with
```swift=
//withStruct
let book: Book = ...
let price: Int = with(book) {
book.checked = true
return book.price
}
```
----
#### Implement scope functions in Swift
----
```swift=
@inlinable
public func withStruct<T: Any, V>(_ value: T, _ block: (inout T) throws -> V) rethrows -> V {
var copy = value
return try block(©)
}
```
```swift=
@inlinable
@discardableResult public func withObject<T: AnyObject, V>(_ value: T, _ block: (T) throws -> V) rethrows -> V {
return try block(value)
}
```
----
```swift=
extension ScopeFunction where Self: Any {
@inlinable
@discardableResult public func `let`<T>(_ block: (inout Self) throws -> T) rethrows -> T {
var copy = self
return try block(©)
}
@inlinable
public func also(_ block: (inout Self) throws -> Void) rethrows -> Self {
var copy = self
try block(©)
return copy
}
}
```
---
### Soft Reminder
#### Assing value type when using scope function
----
```swift=
let dic = [String: String]()
//dic.let { it -> [String: String] in
//dic.also { it -> [String: String] in
withStruct(dic) { it -> [String: String] in
it["Name"] = "Allen"
return it
}.also {
print($0)
}
print("\(dic)")
```
----
```swift=
var dic = [String: String]()
//assign the return value!
dic = withStruct(dic) { it -> [String: String] in
it["Name"] = "Allen"
return it
}.also {
print($0)
}
print("\(dic)")
```
---
### Summary
<font size=5>
| Function | Return value | Value type | Reference type |
|:---------- |:-------------- |:---------- |:-------------- |
| let | Lambda result | v | |
| also | Context object | v | |
| withStruct | Lambda result | v | |
| withObject | Lambda result | | v |
| takeIf | Context object | v | |
</font>
---
### Thank you