Kiến thức phỏng vấn iOS _ Phần 1 : Structures and Classes
Bài đăng này đã không được cập nhật trong 7 năm
Lời nói đầu
Như mọi người đã biết, mỗi khi đi phỏng vấn chúng ta thường phải chuẩn bị rất nhiều thứ, ôn luyện lại kiến thức, nghĩ ra đủ thứ loại vấn đề mà người phỏng vấn sẽ hỏi mình. Nhất là với người đã có kinh nghiệm làm việc thì lại chuẩn bị nhiều hơn những sinh viên sắp hoặc vừa ra trường chưa có kinh nghiệm làm việc tại môi trường công ty. Việc chuẩn bị nhiều thứ như vậy là không thừa, nhưng chúng ta dễ bị choáng ngợp vì đọc cái gì cũng thấy không đủ, càng học càng thấy mới lạ, kiến thức nhiều vô số kể, dẫn đến lan man và tốn nhiều thời gian mà hiệu quả mang lại không thích hợp với mong muốn hiện tại của chúng ta đó là phỏng vấn xin việc. Việc một người phỏng vấn mà rành rõi về các kiến thức cơ bản, core value của một ngôn ngữ lập trình thì luôn được đánh giá cao, bất kể là đã đi làm hay chưa đi làm. Vì vậy, với kinh nghiệm đi làm vài năm, có vài lần phỏng vấn và bị phỏng vấn thì mình rút ra được một kinh nghiệm đó là: chúng ta không nhất thiết phải hiểu biết toàn bộ ngôn ngữ lập trình, nhưng những cái gì ta biết thì phải biết đến tận cùng, đến gốc rễ của nó. Với mong muốn hệ thống lại kiến thức cho bản thân, cũng như cho những người có nhu cầu thì mình sẽ làm một series về các kiến thức cơ bản của iOS để đi phỏng vấn xin việc, code mẫu sẽ là ngôn ngữ Swift.
Phần I: Structures and Classes
Structures và Classes được tạo ra với cùng chung một mục đích là các khối lệnh riêng biệt thể hiện cho một đối tượng, sự vật nào đó. Chúng ta có thể định nghĩa các properties và methods để thêm tính năng cho structures và classes đó.
1. Phân biệt structures và classes.
a. Giống nhau: structures và classes có nhiều điểm giống nhau, và có điều thú vụ nên nhớ là classes nó như là một sự mở rộng của structures, nghĩa là những gì structures có thì class cũng có, và classes có thêm một vài thứ mà structures không có.
- Định nghĩa properties để lưu các giá trị
- Định nghĩa methods để cung cấp các chức năng mình có
- Định nghĩa subscripts để cho phép truy cập đến các giá trị của nó thông qua cú pháp của subscript
- Định nghĩa initializers (các hàm dựng) để đa dạng hơn khi khởi tạo
- Có thể mở rộng thêm các tính năng ngoài những cái được implement mặc định
- Có thể tích hợp protocols để cung cấp các chức năng chuẩn cho một bối cảnh xác định nào đó
b. Những cái mà classes có nhưng structures thì không:
- Có khả năng kế thừa từ một class nào đó. Nhớ là chỉ có thể kế thừa từ một chứ không phải nhiều, iOS không cho phép đa kế thừa.
- Kiểm tra và diễn dịch kiểu của một instance của một class lúc runtime
- Deinitializers (hàm huỷ) sẽ giải phóng tài nguyên của một một thể hiện(instance) của một lớp(class) khi được assigned.
- Bộ đếm tham chiếu (reference counting) cho phép nhiều hơn một tham chiếu đến một class instance. Còn structures không có chức năng này vì khi sử dụng structures để truyền dữ liệu trong chương trình thì nó sẽ được copy ra và ta chỉ sử dụng bản copy này.
Đến đây thì chúng ta sẽ có một thắc mắc là, classes đã bao trùm structures thì tại sao mà structures có thể tồn tại song song với classes. Lý do là:
- Structures là kiểu tham trị, còn classes là kiểu tham chiếu
- Structures thích hợp với việc đóng gói một vài dữ liệu nhỏ, đơn giản và có thể copied vì copying, không tham chiếu, là cách an toàn hơn việc có nhiều tham chiếu đến cùng một thể hiện như của classes. Điều này đặc biệt quan trọng khi truyền một biến đến nhiều classes hoặc các threads, nếu ta sử dụng một bản copy thì ta sẽ không lo lắng bản gốc bị thay đổi khi mà các bản sao bị thay đổi, còn classes thì không nói trước được điều gì.
- Việc dùng structures cũng giúp ta không lo lắng nhiều đến vấn đề memory leak
Vì vậy, nhìn chung thì khi gặp các điều kiện sau thì ta nên dùng structures thay vì dùng classes:
- Muốn đóng gói các dữ liệu nhỏ, đơn giản
- Những giá trị dữ liệu được đóng gói đó cũng sẽ được copy chứ không phải tham chiếu khi ta gán/truyền một thể hiện của structures trong code
- Những properties stored của structure cũng đều là kiểu giá trị, sẽ được copied chứ không referenced
- Structure không cần kế thừa các properties hoặc methods từ các kiểu có sẵn khác.
Như đã biết thì thể hiện của structures thì được cấp phát (allocated) trên stack, và các thể hiện của classes thì được cấp phát trên heap, stack được dùng cho việc cấp phát vùng nhớ tĩnh còn heap được dùng cho việc cấp phát vùng nhớ động , do đó structures có thể thỉnh thoảng nhanh hơn, nhưng vẫn phụ thuộc vào số lượng giá trị chúng ta đang lưu trữ và kích thước của chúng.
Trên đây chỉ là các trường hợp khuyên dùng structure mà thôi, chứ thực tế thì trong hầu hết các trường hợp custom cấu trúc dữ liệu, chúng ta vẫn sẽ định nghĩa class và tạo thể hiện của class đó để tổ chức và quản lý dữ liệu.
2. Cú pháp
struct StructName {
//Define properties and methods
}
class ClassName {
//Define properties and methods
}
3. Class and structure instance
Cả structures và classes đều dùng các cú pháp khởi tạo cho các thể hiện mới. Đơn giản nhất là cú pháp khởi tạo không có tham số truyền vào StructureName()/ ClassName(), khởi tạo một thể hiện của structure hoặc class mà các properties của nó sẽ là các giá trị được định nghĩa mặc định trong nó. Có một điều đặc biệt cần chú ý đó là: ở structures thì khi khởi tạo một thể hiện mới, chúng ta có thể truyền qua các tham số cho các properties của nó, với tên tham số là tên các properties của nó mà không cần định nghĩa hàm init tương ứng. Điều này không áp dụng cho class, class thì dùng method init nào thì ta phải định nghĩa method init đó ra mới sử dụng được. Ví dụ:
struct Point {
var x: Int = 0
var y: Int = 0
}
let pointA = Point()
let pointB = Point(x: 10, y: 20)
4. Structures là kiểu tham trị
Như đã nói ở trên. Chúng ta gán một thể hiện của một structure cho một biến nào đó thì có nghĩa là structure đó được copied ra một bản và được gán cho biến mới. Và do đó, mọi thao tác thay đổi values trên biến mới không làm thay đổi giá trị của structure ban đầu, nghĩa là các biến tách biệt, không có quan hệ gì với nhau. Nó tương tự như ta làm việc với các kiểu cơ bản của Swift - Integers, Booleans, string, array,...
let pointA = Point(x: 10, y; 20)
var pointB = pointA
pointB.x = 30 //pointA = (10, 20), pointB = (30, 20)
5. Classes là kiểu tham chiếu
Không giống với kiểu tham trị ở trên, khi gán cho đến variable, constant, hoặc làm tham số truyền qua function thì chúng ta sẽ tham chiếu trực tiếp đến đối tượng mà không cần copy ra bản mới. Do đó khi một bên thay đổi value thì những bên tham chiếu đến đối tượng đó đều thay đổi theo.
class Man {
var name: String = ""
}
let man = Man()
man.name = "Tuan" // name of man is Tuan
let otherMan = man
otherMan.name = "Leo" // now, name of man is Leo, same new name of otherMan
Nên nhớ khi nói phỏng vấn, man không phải vùng nhớ mà là một biến tham chiếu, nó tham chiếu đến địa chỉ của một thể hiện là Man(). man, otherMan là các biến, còn thể hiện(instance) thì chỉ có duy nhất là Man(), đừng nhầm lẫn. Như ví dụ trên thì đối tượng Man() có 2 tham chiếu đến bản thân nó, reference cout của nó là 2.
Đến đây thì có một điều ta nên lưu ý khi trả lời phỏng vấn, đây có thể là một câu hỏi may rủi vì đơn giản là ta nghĩ nó tương tự. Đó là: NSString, NSDictionary, ... và tương ứng với nó String, Dictionary,... thoạt nhìn thì hai cái này tên gọi tương tự, chức năng tương tự, nhưng về mặt bộ nhớ, dữ liệu thì nó khác biệt, vì NSString, NSDictionary,.. là classes có kiểu tham chiếu, còn String, Dictionary,... lại là structures kiểu tham trị
Lời kết
Trên đây là hệ thống lại kiến thức của bản thân, cũng như tham khảo cái tài liệu chuẩn của Apple và các website uy tín trên thế giới, về structures và classes, giúp ta hiểu được các kiến thức cơ bản về structures và classes đủ để đối phó khi đi phỏng vấn. Tất nhiên trong bài sẽ có nhiều thiếu sót, và nhiều ý chưa được làm rõ và trọn vẹn, nên rất mong được sự góp ý chân thành, mang tính xây dựng và phát triển của tất cả mọi người, để chúng ta có thể cùng nhau củng cố kiến thức và tiến bộ hơn. Xin chân thành cảm ơn.
All rights reserved