Nên dùng struct hay class trong Swift phần 1
Bài viết phân tích sự khác biệt giữa struct và class trong Swift, giải thích về References Type và Values Type với các ví dụ cụ thể. Đây là phần đầu tiên trong loạt bài hướng dẫn lập trình viên Swift cách lựa chọn giữa struct và class cho từng trường hợp sử dụng.

Giới thiệu
Mấy lần trước mình có viết mấy bài như:
http://niviki.com/2017/04/quan-ly-bo-nho-trong-swift/
http://niviki.com/2017/03/toan-tap-protocols-trong-swift-3/
Thiệt tình mấy bài này dài quá, mỗi bài trên 1k5 từ. Nên lần này mình tách ra nhiều phần nhỏ viết cho mọi người dễ đọc, mình cũng có động lực viết hơn. Chứ viêt 1 bài dài cực lắm.
References Type và Values Type
Ở bài Quản lý bộ nhớ với Swift, mình có nói về kiểu references ( tham chiếu ) và value ( tham trị ) này rồi, trong bài đó có hình ảnh minh họa rõ ràng nữa, bạn nào chưa biết phần này thì xem qua nhé.
Apple cũng hướng Swift theo Value Oriented Programming (VoP), có nghĩa là đa số kiểu dữ liệu của Swift là value type như booleans, integers, strings, tuples, and enums. Cả array và dictionary cũng là value type luôn
var a = ["ni", "vi", "ki"]
var b = a
a.append(".com")
print(b.count) // 3
Và một mảng kiểu reference type cũng như mảng value type luôn:
class Student {
var name: String
init(name: String) {
self.name = name
}
}
let st1 = Student(name: "Khoa")
let st2 = Student(name: "Alex")
let st3 = Student(name: "My")
var students1 = [st1,st2]
var students2 = students1
students1.append(st3)
print(students2.count) // 2
Còn với reference type thì sẽ khác:
var st1 = Student(name: "Khoa")
var st2 = Student(name: "Alex")
st2 = st1
st1.name = "Khoa Nguyen"
print(st2.name) // Khoa Nguyen
Mình nhắc lại là đáng lẽ mình sẽ vẽ hình minh họa nhưng bài Quản lý bộ nhớ với Swift mình có vẽ cực kỳ chi tiết rồi, bạn có thể tham khảo thêm nhé.
Tóm lại, kiểu reference khi gán bằng thì sẽ chia sẻ địa chỉ của giá trị trong bộ nhớ với thằng được gán bằng, tức là sẽ có nhiều owners có quyền thay đổi giá trị đó. Như ví dụ trên khi gán st2 = st1 thì st1 đã chia sẻ địa chỉ của Student("Khoa Nguyen") cho thằng st2. Do st1 và st2 cùng là owners nên 1 thằng thay đổi thì cả 2 sẽ bị ảnh hưởng theo.
Ngược lại, kiểu value thì mỗi lần gán bằng giá trị sẽ được copy ra và mỗi thằng sẽ được 1 bản copy. Anh thay đổi thì kệ anh tôi không liên quan nữa
Tại sao dùng Struct?
Trong Swift, ngoài class thì closure cũng là reference type, nhưng để đa số mọi người sẽ phân vân giữa nên chọn struct hay class nhiều hơn vì closure nó thuộc thể loại khác rồi, mình sẽ viết về nó ở những bài sau nhé. Vì thế chúng ta sẽ đặt câu hỏi tại sao dùng struct, nó có ưu điểm gì?
Struct giảm đi mối quan hệ dây mơ rễ má trong code
Đầu tiên dễ thấy nhất là struct giảm đi mối quan hệ dây mơ rễ má trong code của bạn. Ví dụ bạn cần truyền param qua lại giữa các ViewController, nếu dùng class thì các ViewController đều là owner của các params này. Khi một ViewController thay đổi giá trị của params thì chúng sẽ bị ảnh hưởng ở toàn ứng dụng. Ví dụ dễ thấy nhất là khi truyền param khi xài segue hay Core Data.
Ví dụ bạn có 2 ViewController (VC): MainVC và ScoreVC.
Bạn cần truyền id từ MainVC qua các VC khác để dùng.
import UIKit
class Student {
var id: String
init(id: String) {
self.id = id
}
}
class MainVC: UIViewController {
let khoa = Student(id: "1234")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear() MainVC ")
print("id: \(khoa.id)")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
if let secondVC = segue.destination as? ScoreVC {
if let st = sender as? Student {
secondVC.student = st
}
}
}
}
@IBAction func goBtn(_ sender: Any) {
performSegue(withIdentifier: "segue", sender: khoa)
}
}
Và ở ScoreVC, bạn lỡ tay modify cái id này:
import UIKit
class ScoreVC: UIViewController {
var student: Student!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func back(_ sender: Any) {
student.id = "00000"
dismiss(animated: true, completion: nil)
}
}
Thì console sẽ in ra như sau:
viewWillAppear() MainVC
id: 1234
viewWillAppear() MainVC
id: 00000
Id đã bị thay đổi, và nếu bạn tiếp tục pass cái id này sang các ViewController khác thì sẽ có bugs đúng không nào
Thread-safe
Thread-unsafe tức là có nhiều thread dùng chung một giá trị. struct hiển nhiên là Thread-safe rồi, vì mỗi thread sẽ có mỗi bản copy riêng, chúng đập lập với nhau, thread muốn làm gì làm cũng chả ảnh hưởng gì cả.
To be continued
Bài này mình đã nói về ưu điểm của Struct, vậy nó có khuyết điểm gì và class có ưu điểm gì hơn struct. Hẹn mọi người ở bài sau nhé. Mọi code/project demo mình đều up ở Github nhé: https://github.com/KhoaVanNguyen/Swift-Tutorials
Related Posts
Discover more content you might enjoy

Lộ trình + Resources học Swift và IOS từ cơ bản đến nâng cao
Bài viết chia sẻ lộ trình học Swift và iOS từ cơ bản đến nâng cao dựa trên trải nghiệm thực tế của tác giả. Nội dung bao gồm các tài nguyên học tập chất lượng như sách, khóa học trực tuyến từ Devslopes, Ray Wenderlich và Apple, cùng với lời khuyên về cách tiếp cận hiệu quả cho người mới bắt đầu.

Lập trình di động với Ionic - Có nên không?
Bài viết đánh giá framework Ionic cho phát triển ứng dụng di động đa nền tảng, phân tích ưu điểm như mã nguồn mở, tài liệu dễ hiểu, component đầy đủ và hệ sinh thái phong phú. Tác giả so sánh Ionic với React Native và chia sẻ kinh nghiệm thực tế khi sử dụng framework này.

Lập trình IOS Swift 3 + Xcode 8 Sơn Tùng MTP Playlist App
Hướng dẫn lập trình iOS cơ bản thông qua việc xây dựng ứng dụng playlist nhạc Sơn Tùng MTP với Swift 3 và Xcode 8. Bài viết bao gồm các kỹ thuật Autolayout, TableView, Data modeling, mô hình MVC và cách sử dụng segue, phù hợp cho người đã có kiến thức cơ bản về Swift và Xcode.

Game Theory trong thời đại AI: Khi máy móc tham gia vào "trò chơi"
Bài viết phân tích sự giao thoa giữa lý thuyết trò chơi (Game Theory) và trí tuệ nhân tạo, giải thích cách AI đang thay đổi các nguyên lý cân bằng Nash và chiến lược tối ưu. Tác giả đưa ra các ví dụ thực tế về ứng dụng trong kinh doanh, giao thông và an ninh mạng.
![[Case Study] Vừa đi du lịch vừa làm việc kiếm $4250 trong 80h](/_next/image?url=https%3A%2F%2Fres.cloudinary.com%2Fkhoanguyen1505%2Fimage%2Fupload%2Fv1751208916%2Fkhoa_blog%2FCase_Study_V%25E1%25BB%25ABa_%25C4%2591i_du_l%25E1%25BB%258Bch_v%25E1%25BB%25ABa_l%25C3%25A0m_vi%25E1%25BB%2587c_ki%25E1%25BA%25BFm_4250_t%2F114e3cbb-4dae-4e41-aa63-f5742df3ce07_2240x1260.png.jpg&w=828&q=75)
[Case Study] Vừa đi du lịch vừa làm việc kiếm $4250 trong 80h
Trải nghiệm thực tế về việc làm remote kết hợp du lịch xuyên Đông Nam Á theo phong cách Tây balo. Bài viết chia sẻ chi tiết cách tận dụng thời gian chết để làm việc hiệu quả, tham gia các cuộc thi blockchain để kiếm thêm thu nhập, và những bài học thực tế về cân bằng công việc-du lịch khi không có môi trường làm việc lý tưởng.

Day 19 - Profitable MVP in 30 Days - Đó là một câu chuyện buồn
Bài viết ngày 19 của thử thách xây dựng MVP có lợi nhuận, tác giả chia sẻ câu chuyện buồn về trải nghiệm làm việc với designer trên Fiverr trong bối cảnh đại dịch COVID-19. Bài viết phản ánh về sự vội vàng trong đánh giá, cảm xúc hối hận, và bài học về sự thấu cảm, kiên nhẫn trong giao tiếp trực tuyến, đặc biệt trong thời điểm khó khăn toàn cầu.