logo
hero image

Swift Ownership & Borrowing

Cara baru untuk mengelola memori di Swift 🕊️
7 December 2024 · 6 Minutes

Seperti yang telah kita ketahui, Swift mempunyai 2 tipe data yaitu Reference Type dan Value Type. Reference Type adalah tipe data yang disimpan di heap memory yang dikelola oleh Swift menggunakan ARC (Automatic Reference Counting).

Sedangkan Value Type adalah tipe data yang disimpan di stack memory dan jika dilakukan assignment ke variable lain atau dipassing ke sebuah function maka akan selalu dicopy valuenya.

Sebelumnya saya pernah menulis artikel tentang Automatic Reference Counting (ARC) pada Swift, kalian bisa membacanya di sini.

Problemnya adalah ketika kita mempunyai sebuah variable dengan tipe data Value Type seperti struct yang berukuran sangat besar, maka ketika kita melakukan assignment atau passing ke sebuah function maka valuenya akan selalu dicopy, yang berarti akan memakan waktu dan memori yang cukup besar juga.

Oke, kalau gitu kenapa tidak menggunakan Reference Type saja seperti class? Sebenarnya bisa saja, namun jika kita ingin performa yang lebih baik, cara ini tidak direkomendasikan karena tipe data class akan disimpan di heap memory yang dikelola oleh ARC, yang berarti ada proses retain release, kemudian kita harus memikirkan tentang retain cycle yang bisa menyebabkan memory leaks, dan juga menurut benchmark yang dilakukan oleh Infinum ternyata ARC mempunyai dampak pada performa yang cukup signifikan.

ARC PerformanceARC Performance

Untuk mengatasi masalah tersebut, Swift 5.9 memperkenalkan konsep Ownership.

Apa itu Ownership?

Ownership adalah konsep dan aturan yang digunakan untuk mengelola memori di Swift secara efisien dan aman, dimana sebuah variabel hanya bisa dimiliki oleh satu owner saja, dan owner tersebut bertanggung jawab untuk menghapus variabel dari memori ketika variabel tersebut sudah tidak diperlukan lagi.

Konsep Ownership ini mirip dengan konsep Ownership di Rust, dimana setiap variabel hanya bisa dimiliki oleh satu owner saja, dan ketika variabel tersebut dipassing ke variabel lain misalnya, maka ownership dari variabel tersebut akan dipindahkan ke variabel lain tersebut.

Seperti di Rust, kita juga bisa melakukan Borrowing, dimana kita bisa meminjam value dari suatu variabel tanpa harus ada perpindahan ownership.

Perbedaan dengan sistem Ownership di Rust adalah sistem Ownership di Swift ini bersifat opsional, jadi kita bisa gunakan di bagian kode yang membutuhkan performa tinggi saja.

It is the core team's expectation that ownership can be delivered as an opt-in enhancement to Swift. Programmers should be able to largely ignore ownership and not suffer for it. If this expectation proves to not be satisfiable, we will reject ownership rather than imposing substantial burdens on regular programs.
Swift Ownership Manifesto

~Copyable

Hal pertama yang perlu kita lakukan untuk menggunakan sistem Ownership adalah dengan menambahkan ~Copyable pada Struct atau Enum kita.

Secara default, Struct & Enum di Swift adalah Copyable, yang berarti ketika kita melakukan assignment atau passing ke sebuah function, maka valuenya akan selalu dicopy. Namun, kita bisa mengubahnya menjadi Non-Copyable dengan cara menambahkan ~Copyable pada Struct atau Enum kita.

Contohnya seperti ini:

icon
1struct Book: ~Copyable {
2 var price: String
3}
4
5let book = Book(price: 100_000)
6let book2 = book
7print(book2.price) // ✅ OK
8print(book.price) // ❌ Compilation Error: 'book' used after consume

Pada contoh di atas, kita membuat Non-Copyable struct Book dan kita melakukan assignment let book2 = book, ownership dari book akan dipindahkan ke book2, sehingga ketika kita mencoba mengakses book.price maka akan terjadi error pada saat dicompile.

Limitasi

Berikut adalah beberapa limitasi dari ~Copyable untuk saat ini:

  • Hanya bisa digunakan pada Struct & Enum

  • Struct & Enum yang menggunakan ~Copyable, properti2-nya juga harus ~Copyable

  • Belum mendukung Generic

Borrowing

Jika kita tidak ingin memindahkan ownership dari suatu variabel pada saat passing variabel tersebut ke suatu function, maka kita bisa melakukan Borrowing. Borrowing adalah proses meminjam value dari suatu variabel tanpa memindahkan ownership dari variabel tersebut.

Berikut adalah contoh penggunaan Borrowing:

icon
1struct Book: ~Copyable {
2 var price: Int
3
4 borrowing func read() {
5 print("Reading book...")
6 }
7}
8
9func describeBook(_ book: borrowing Book) {
10 print("Price: \(book.price)")
11}

Jika functionnya berada di luar struct maka kita perlu menambahkan keyword borrowing pada parameter functionnya.

Tapi jika functionnya di dalam struct maka kita perlu menambahkan keyword borrowing pada awal deklarasi functionnya dan secara default sebenarnya tipenya adalah borrowing, jadi kita bisa hapus keyword borrowing nya.

icon
1struct Book: ~Copyable {
2 var price: Int
3
4 func read() {
5 print("Reading book...")
6 }
7}

Inout

Seperti borrowing, inout juga digunakan untuk meminjam value dari suatu variabel, namun inout dapat digunakan jika kita ingin mengubah value dari variabel tersebut.

Berikut adalah contoh penggunaan inout:

icon
1func modifyPrice(_ book: inout Book) {
2 book.price = 999
3}
4
5modifyPrice(&book)

Pada kode di atas, kita membuat function modifyPrice yang menerima parameter inout Book, dan kita memanggil function tersebut dengan menambahkan & sebelum variabel book.

Consuming

Jika kita ingin memindahkan ownership dari suatu variabel pada saat passing variabel ke suatu function, maka kita bisa melakukan Consuming. Dan apabila sudah mencapai akhir dari scope function tersebut, maka variabel tersebut akan dihapus dari memori.

Berikut adalah contoh penggunaan Consuming:

icon
1struct Book: ~Copyable {
2 var price: Int
3
4 consuming func delete() {
5 print("Deleting book from the database...")
6 }
7}

Pada kode di atas, kita menambahkan keyword consuming pada function delete(), sehingga ketika kita memanggil function delete() 2x maka akan terjadi error pada saat dicompile.

icon
1let book = Book(price: 100_000)
2book.delete() // ✅ OK
3book.delete() // ❌ Compilation Error: 'book' consumed more than once

Discard

Terakhir, ada keyword discard yang digunakan untuk mencegah deinit dipanggil pada saat variabel tersebut dihapus dari memori.

Berikut adalah contoh penggunaan discard:

icon
1struct Book: ~Copyable {
2 var price: Int
3
4 consuming func delete() {
5 print("Deleting book from the database...")
6 discard self
7 }
8
9 deinit {
10 print("Deleting book from the database...")
11 }
12}

Pada kode di atas, kita menambahkan keyword discard self pada function delete(), sehingga ketika kita memanggil function delete() maka deinit tidak akan dipanggil.

Performance Benchmark

Infinum telah melakukan benchmark terhadap sistem Ownership di Swift, berikut adalah hasilnya:

BorrowingBorrowing
ConsumingConsuming


Sekarang, kita sudah belajar tentang Ownership & Borrowing di Swift, agar lebih mudah diingat, berikut adalah perbedaan utama antara borrowing, inout, dan consuming:

  • borrowing: Digunakan untuk meminjam value dari suatu variabel (Read Only).

  • inout: Digunakan untuk meminjam value dari suatu variabel dan kita bisa mengubah valuenya.

  • consuming: Digunakan untuk memindahkan ownership dari suatu variabel.

Oke mungkin itu saja yang bisa saya bagikan kali ini, kalau kamu merasa artikel ini bermanfaat silakan Like & Share artikel ini ke teman-teman kamu atau jika kamu punya pertanyaan, tulis aja di kolom komentar, Thank you! 😁 🙏

Referensi:

iOS Development
Swift
Memory Management

Written by :
Alfin Syahruddin
Developer · Stock Trader · Libertarian · Freethinker

Always open to new ideas. 🕊️

Loading...

Related articles

Articles that you might want to read.

hero image
Sharing Code iOS & Android dengan Rust

Tutorial memanggil kode Rust di Swift dan Kotlin menggunakan UniFFI.

25 August 2024 · 8 Minutes
Cross Platform
Rust
Swift
Kotlin
hero image
CI/CD aplikasi iOS dengan Fastlane dan Github Actions

Otomatisasi build, testing, screenshot, dan deployment aplikasi iOS ke Testflight & AppStore.

24 September 2023 · 9 Minutes
iOS Development
CI/CD
Fastlane
Github Actions
hero image
Testable Code

Menulis kode yang mudah untuk di-test pada Swift.

1 May 2023 · 8 Minutes
iOS Development
Swift
Testing
All rights reserved © Alfin Syahruddin · 2019
RSS Feed