Top 30+ câu hỏi phỏng vấn Objective-C từ lý thuyết đến thực hành

Nếu bạn đang chuẩn bị cho một buổi phỏng vấn vị trí lập trình viên iOS, có thể bạn sẽ gặp những câu hỏi xoay quanh Objective-C. Bởi lẽ Objective-C vẫn hiện diện trong nhiều dự án cũ và đòi hỏi bạn phải hiểu rõ mới có thể bảo trì hoặc mở rộng. Trong bài viết này, ITviec đã tổng hợp hơn 30 câu hỏi phỏng vấn Objective-C từ lý thuyết đến thực hành. Cùng tìm hiểu và luyện tập trước khi bước vào phỏng vấn nhé!

Đọc bài viết để hiểu rõ hơn:

  • Câu hỏi phỏng vấn Objective-C mức sơ cấp (Junior Level)
  • Câu hỏi phỏng vấn Objective-C mức trung cấp (Middle Level)
  • Câu hỏi phỏng vấn Objective-C mức cao cấp (Senior Level)

Đọc chi tiết: Objective-C là gì? Có còn phù hợp để học trong năm 2025?

Câu hỏi phỏng vấn Objective-C mức sơ cấp (Junior Level)

Objective-C hỗ trợ kiểu dữ liệu động như thế nào?

Objective-C hỗ trợ kiểu dữ liệu động (dynamic typing) thông qua biến đặc biệt id. Biến id có thể lưu trữ bất kỳ đối tượng nào mà không cần xác định kiểu cụ thể tại thời điểm biên dịch. Từ đó mang lại sự linh hoạt cao trong việc xử lý đối tượng.

Bên cạnh đó, Objective-C còn cung cấp các phương thức kiểm tra kiểm tại thời điểm chạy như respondsToSelector:, isKindOfClass:, isMemberOfClass: hoặc conformsToProtocol:. Những công cụ này giúp đảm bảo an toàn khi làm việc với các đối tượng có kiểu không cố định.

Ngoài ra, hệ thống runtime message passing còn cho phép Objective-C gửi thông điệp đến đối tượng mà không cần kiểm tra kiểu trước, tạo điều kiện để các đối tượng đa hình (polymorphic) hoạt động một cách linh hoạt và tự do hơn trong quá trình thực thi.

Giải thích khái niệm gửi tin nhắn trong Objective-C.

Trong Objective-C, khái niệm “gửi tin nhắn” (message sending) là cơ chế được sử dụng để gọi phương thức trên một đối tượng. Khác với C++ hay Java, Objective-C sẽ gửi một thông điệp đến đối tượng này và đối tượng đó sẽ quyết định có thực thi hay không.

Sự khác biệt giữa #import và #include trong Objective-C là gì?

Trong Objective-C, cả #import#include đều được dùng để chèn nội dung của file header vào file hiện tại. Tuy nhiên, hai chỉ thị này có cách hoạt động khác nhau.

  • #import: Chỉ chèn file một lần duy nhất, bất kể được gọi nhiều lần trong mã nguồn. Chỉ thị này giúp tránh tình trạng chèn trùng lặp, từ đó ngăn ngừa lỗi biên dịch do định nghĩa trùng lặp.
  • #include: Mỗi lần được gọi, nội dung file sẽ được chèn lại. Để tránh chèn trùng lặp, lập trình viên phải dùng thêm các chỉ thị tiền xử lý như #ifndef, #define#endif.

Vì sự tiện lợi và an toàn, #import được ưu tiên trong hầu hết các dự án Objective-C hiện đại.

Giải thích sự khác biệt giữa tính chất atomic và nonatomic trong Objective-C.

Trong Objective-C, khi khai báo thuộc tính (@property), lập trình viên có thể chỉ định tính chất atomic hoặc nonatomic để kiểm soát cách thuộc tính đó được truy cập trong môi trường đa luồng. Trong đó:

  • Atomic: Mang đến cơ chế đồng bộ giữa các luồng, phù hợp khi cần đảm bảo tính toàn vẹn dữ liệu trong ứng dụng đa luồng. Tuy nhiên, atomic không đảm bảo đối tượng fully thread-safe. Với atomic, khi một luồng đang đọc hoặc ghi dữ liệu, các luồng khác sẽ phải chờ cho đến khi thao tác hoàn tất, giúp tránh xung đột dữ liệu nhưng có thể làm giảm hiệu năng.
  • Nonatomic: Không có cơ chế đồng bộ nên các luồng có thể hoạt động song song, chồng chéo lên nhau. Thường được dùng trong các tình huống đơn luồng hoặc khi hiệu năng là yếu tố ưu tiên. Với nonatomic, việc truy cập và thay đổi dữ liệu diễn ra nhanh hơn nhưng đổi lại có thể xảy ra lỗi hoặc hành vi không xác định.  

Delegate là gì? Delegate có thể được giữ lại không?

Delegate là một đối tượng được uỷ quyền để thực hiện thay thế hoặc hỗ trợ xử lý một hành động, thường là để phản hồi các sự kiện. Delegate cho phép các lớp giao tiếp linh hoạt với nhau theo mô hình “bên A gửi yêu cầu – bên B phản hồi” mà không cần ràng buộc trực tiếp về mặt cấu trúc.

Về mặt kỹ thuật, delegate có thể được giữ lại nếu thuộc tính delegate được khai báo với từ khoá strong. Tuy nhiên, điều này không được khuyến khích, vì delegate thường đã được một đối tượng khác giữ. Nếu giữ lại thêm lần nữa, có thể dẫn đến vòng lặp giữ (retain cycle), khiến bộ nhớ không được giải phóng đúng cách.

Để tránh tình trạng này, delegate nên được khai báo với từ khoá weak. Việc sử dụng weak reference đảm bảo rằng đối tượng giữ delegate không làm tăng số lượng tham chiếu đến delegate, từ đó giúp tránh retain cycle và đảm bảo quá trình quản lý bộ nhớ diễn ra chính xác.

Làm thế nào đưa nil vào một category/mảng?

Trong Objective-C, không thể trực tiếp đưa nil vào một category hoặc một mảng. Bởi nil thường được dùng để đánh dấu kết thúc danh sách đối tượng trong nhiều API. Đồng thời, nil cũng không phải là một đối tượng nên không thể được lưu trong mảng.

Nêu hiểu biết của bạn về Protocol trong Objective-C.

Protocol trong Objective-C là một tập hợp các phương thức mà một lớp có thể cam kết thực hiện. Nó giống như một “giao kèo” về hành vi, định nghĩa cái gì cần được thực hiện nhưng không chứa phần triển khai cụ thể. 

Protocol thường được dùng để định nghĩa interface chung cho các đối tượng không liên quan về mặt kế thừa, hoặc để thiết kế delegate pattern. Có thể đánh dấu các phương thức trong protocol là @optional hoặc @required, giúp linh hoạt hơn khi áp dụng trong thực tế.

Câu hỏi phỏng vấn Objective-C trung cấp (Middle Level)

Hãy mô tả cách Objective-C xử lý việc quản lý bộ nhớ.

Objective-C sử dụng mô hình quản lý bộ nhớ dựa trên Reference Counting (đếm số lượng tham chiếu). Mỗi đối tượng trong bộ nhớ đều có một bộ đếm gọi là retain count. Khi một đối tượng được tạo mới hoặc được giữ lại (retained), retain count sẽ tăng. Ngược lại, khi đối tượng được giải phóng (release), retain count sẽ giảm. Khi bộ đếm bằng 0, đối tượng sẽ được tự động giải phóng hoàn toàn khỏi bộ nhớ.

Để đơn giản hóa quá trình này, Objective-C áp dụng công nghệ Automatic Reference Counting (ARC). ARC tự động chèn các lệnh retain, release và autorelease trong quá trình biên dịch, giúp loại bỏ nhu cầu quản lý thủ công như trong mô hình Manual Retain-Release (MRR). Nhờ đó, ARC góp phần giảm thiểu lỗi rò rỉ bộ nhớ (memory leak) và lỗi con trỏ treo (dangling pointer), đồng thời giúp mã nguồn an toàn và dễ bảo trì hơn.

Cơ chế phát hành tự động (Autorelease Pool) là gì?

Autorelease Pool là một cơ chế quản lý bộ nhớ trong Objective-C, cho phép hoãn giải phóng các đối tượng đã được đánh dấu autorelease đến khi pool kết thúc. Cơ chế này giúp giảm gánh nặng phải release thủ công từng đối tượng, đồng thời tối ưu hiệu năng và hạn chế rò rỉ bộ nhớ, đặc biệt trong các vòng lặp tạo nhiều đối tượng tạm thời.

Vai trò của @selector trong Objective-C là gì?

Selector trong Objective-C có hai vai trò:

  • Khi viết mã: Selector đơn giản là tên của một phương thức được dùng trong lệnh gửi tin nhắn, ví dụ: [object doSomething].
  • Khi biên dịch: Selector trở thành một định danh duy nhất (kiểu SEL) đại diện cho tên phương thức đó. Tất cả các phương thức có cùng tên sẽ chia sẻ cùng một selector.

Objective-C xử lý ngoại lệ như thế nào?

Objective-C có 2 kiểu chính để xử lý exception phổ biến:

Cách thứ 1 là dùng các khối lệnh @try, @catch, @finally và từ khóa @throw.

  • @try: Đây là khối chứa đoạn code có thể phát sinh lỗi (ngoại lệ). Nếu lỗi xuất hiện trong khối này, quá trình thực thi sẽ chuyển sang @catch.
  • @catch: Khối này được dùng để xử lý ngoại lệ. Có thể khai báo nhiều khối @catch để xử lý các loại lỗi khác nhau, tuỳ theo kiểu ngoại lệ phát sinh.
  • @finally: Dù có lỗi hay không thì khối @finally vẫn được thực thi. Khối này thường được dùng để giải phóng tài nguyên, đóng file hoặc thực hiện các bước dọn dẹp cần thiết.
  • @throw: Dùng để ném một ngoại lệ, thường là đối tượng thuộc lớp NSException hoặc lớp con.

Cách thứ 2 là sử dụng các hệ thống có sẵn được cung cấp trong Objective-C dựa trên lớp NSException, với một số loại phổ biến như NSRangeException, NSInvalidArgumentException,…

Ngoài ra, lập trình viên cũng có thể tạo ngoại lệ tuỳ chỉnh nếu cần. Tuy nhiên trong thực tế, Objective-C thường sử dụng cơ chế xử lý lỗi bằng NSError hơn là dùng ngoại lệ, để tránh crash ứng dụng.

Sự khác nhau giữa retain và assigned trong Objective-C là gì?

Thuộc tínhRetainAssign
Đối tượng áp dụngDùng cho các đối tượng kế thừa từ NSObjectDùng cho kiểu dữ liệu nguyên thủy (int, BOOL, float, struct,…) 
Cách hoạt độngSetter sẽ “retain” giá trị mới và “release” giá trị cũSetter chỉ gán giá trị, không giữ lại
Quản lý bộ nhớTăng retain count nhằm đảm bảo đối tượng mới không bị giải phóng sớmKhông ảnh hưởng đến retain count,  bộ nhớ do nơi khác quản lý 
Rủi ro khi dùng saiCó thể gây retain cycle hoặc memory leakNếu gán đối tượng, có thể dẫn đến dangling pointer khi đối tượng bị giải phóng
Tính chấtGiữ quyền sở hữu đối tượng được gánKhông giữ quyền sở hữu

Khi nào cần sử dụng NSArray và NSMutableArray?

NSArray là mảng không thay đổi (immutable) thường được dùng khi cần một tập hợp dữ liệu cố định, không thay đổi trong suốt quá trình chạy chương trình. Sau khi khởi tạo, không thể thêm, xoá hay chỉnh sửa phần tử. NSArray thích hợp cho: Dữ liệu cấu hình; Danh sách tham chiếu; Các giá trị hằng số.

NSMutableArray là mảng có thể thay đổi (mutable) thường được dùng khi cần một danh sách linh hoạt, có thể cập nhật nội dung, thêm, xoá, sửa phần tử bất kỳ thời điểm. NSMutableArray thích hợp cho: Dữ liệu nhập từ người dùng; Danh sách nhận từ server; Các tình huống cần thao tác thường xuyên trên mảng.

Nhìn chung: NSArray an toàn cho việc đọc đa luồng và được ưu tiên khi phơi bày dữ liệu ra bên ngoài. Trong khi đó, NSMutableArray linh hoạt nhưng đòi hỏi phải có cơ chế đồng bộ hóa cẩn thận nếu dùng trong môi trường đa luồng

Làm thế nào để tạo một phương thức tĩnh (static method)?

Để khai báo một phương thức tĩnh, có thể dùng từ khóa static. Sau đó gọi qua tên lớp mà không cần tạo đối tượng. Ví dụ:

public class Example {
    public static void myStaticMethod() {
        System.out.println("Hello from static method!");
    }
}

Tìm lỗi trong đoạn mã sau

SMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"value" forKey:nil];

Đoạn code này sẽ gây ra lỗi (ngoại lệ) vì key không được phép là nil trong một dictionary. Để khắc phục, cần điều chỉnh key là một đối tượng hợp lệ và không phải nil.

Bạn hiểu thế nào về cách thức hoạt động của @synthesize trong đoạn code sau:

@interface MyClass : NSObject
@property (strong, nonatomic) NSString *name;
@end
@implementation MyClass
@synthesize name = _name;
@end

Trong đoạn mã trên, @synthesize name = _name; sẽ tự động tạo ra phương thức getter -namesetter -setName: cho thuộc tính name, đồng thời sử dụng biến instance _name để lưu giá trị.

Khối (block) trong Objective-C là gì và nó khác với closure trong các ngôn ngữ lập trình khác như thế nào?

Tiêu chíKhối trong Objective-CClosure trong Swift 
Định nghĩaĐoạn mã có thể được lưu trữ và thực thi sau; có thể capture biến cục bộHàm ẩn danh (anonymous function) có thể capture và sử dụng biến bên ngoài phạm vi khai báo
Khả năng capture biếnCần khai báo biến với block nếu muốn sửa đổiCó thể sửa đổi trực tiếp (không cần từ khóa đặc biệt) 
Cú phápDài dòng, kế thừa từ C, khó đọc với người mới bắt đầuNgắn gọn, rõ ràng và dễ viết hơn
Quản lý bộ nhớDễ gây retain cycle nếu không dùng đúng weak hoặc strong, cần copy block thủ công trong 1 số trường hợpSwift dùng ARC, xử lý retain cycle đơn giản hơn
Khả năng sử dụng lâu dàiPhải dùng copy nếu muốn block tồn tại trên heapKhông cần thao tác thêm vì closures được quản lý tự động
Ứng dụng phổ biếnCallbacks, animation, completion handlers trong Cocoa / UIKitEvent handlers, async code, functional programming

Nêu hiểu biết của bạn về KVO (Key-Value Observing) trong Objective C

KVO (Key-Value Observing) trong Objective-C là cơ chế cho phép một đối tượng theo dõi sự thay đổi giá trị của một thuộc tính trên đối tượng khác. Khi thuộc tính được quan sát thay đổi, hệ thống sẽ tự động thông báo cho observer. KVO thường dùng để tách biệt logic theo dõi trạng thái, thuận tiện trong các mô hình như MVC. 

Việc sử dụng KVO yêu cầu gọi addObserver:forKeyPath:options:context: để đăng ký và override observeValueForKeyPath:ofObject:change:context: để xử lý thay đổi. Sau khi không dùng nữa, cần gọi removeObserver: để tránh crash.

Phương thức dealloc là gì? Giải thích ý nghĩa của phương thức này trong đoạn mã sau:

@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation MyClass
- (void)dealloc {
    NSLog(@"MyClass instance with name %@ is being deallocated.", self.name);
    [super dealloc];
}
@end

Phương thức dealloc trong Objective-C được sử dụng để giải phóng tài nguyên mà đối tượng đang giữ trước khi bị hệ thống thu hồi bộ nhớ. Đây là nơi lập trình viên thực hiện các thao tác dọn dẹp như giải phóng bộ nhớ, đóng các file đang mở hoặc huỷ đăng ký các observer đã được thiết lập trong suốt vòng đời của đối tượng. 

Trong đoạn mã trên, phương thức dealloc sẽ in ra thông báo khi một instance của lớp MyClass bị thu hồi. Đồng thời, cho biết giá trị thuộc tính name của đối tượng đang được dọn dẹp. Lệnh gọi [super dealloc] đảm bảo quá trình dọn dẹp được thực hiện đầy đủ bằng cách gọi phương thức dealloc của lớp cha.

Output của đoạn mã sau sẽ là gì?

NSArray *array = @[@1, @2, @3]; 
NSLog(@"%@", [array objectAtIndex:1]);

Output là 2. Phương thức objectAtIndex dùng để truy xuất đối tượng ở vị trí chỉ định trong mảng. Index của mảng trong Objective C bắt đầu từ 0 nên khi set objectAtindex == 1 thì kết quả sẽ là 2. 

Đoạn mã sau sẽ cho kết quả gì?

@interface MyClass: NSObject 
@property (nonatomic, strong) NSString *text; 
@end 
@implementation MyClass 
@synthesize text; 
- (void)dealloc { 
    NSLog(@"Deallocating %@", [self.text uppercaseString]); 
} 
@end 
int main() { 
    MyClass *obj = [[MyClass alloc] init]; 
    obj.text = @"hello"; 
    obj = nil; 
    return 0; 
}

Kết quả của đoạn code trên sẽ là “Deallocating HELLO”. Phương thức dealloc sẽ ghi log chuỗi ký tự viết hoa của thuộc tính text.

Câu hỏi phỏng vấn Objective-C cấp độ cao (Senior Level)

Sự khác biệt giữa hàm (Function) và thủ tục (Procedure) được lưu trữ trong .NET là gì? 

HàmThủ tục 
Luôn trả về một giá trị sau khi thực thi câu lệnhCó thể trả về giá trị thông qua tham số IN OUT và OUT
Hàm có chứa câu lệnh DML (INSERT, UPDATE, DELETE) không thể được gọi từ truy vấn SQL. Hàm giao dịch độc lập (autonomous transaction functions) có thể được gọi từ truy vấn SQL.Không thể được gọi trực tiếp từ câu lệnh SQL.
Mỗi lần biên dịch hàm, nó sẽ cho ra kết quả dựa trên đầu vàoChỉ biên dịch một lần và có thể được gọi lại nhiều lần mà không cần biên dịch lại.
Không thể trả về nhiều tập kết quả.Có thể trả về nhiều tập kết quả.
Có thể được gọi từ thủ tục lưu trữ.Không thể được gọi từ hàm.
Chỉ dùng để đọc dữ liệu.Có thể dùng để đọc và chỉnh sửa dữ liệu
Lệnh RETURN của hàm trả về điều khiển cùng với giá trị của hàm cho chương trình gọi.Lệnh RETURN của thủ tục chỉ trả về điều khiển, không trả về giá trị.
Không hỗ trợ khối try-catch.Hỗ trợ try-catch để xử lý lỗi.
Có thể được sử dụng trong câu lệnh SELECTKhông thể sử dụng trong câu lệnh SELECT.
Không hỗ trợ quản lý giao dịch.Hỗ trợ quản lý giao dịch.
Chỉ có thể sử dụng biến bảng (table variable)Có thể sử dụng cả bảng tạm và biến bảng để lưu dữ liệu tạm thời.

Giải thích các loại giao thức (protocol) trong Objective-C?

Trong Objective-C, giao thức là một tập hợp các phương thức mà các lớp có thể tuân thủ (conform) để thực thi những chức năng nhất định. Có hai loại giao thức chính được sử dụng phổ biến: giao thức chính thức (Formal Protocol) và giao thức không chính thức (Informal Protocol).

  • Giao thức chính thức (Formal Protocol): Đây là giao thức được định danh rõ ràng, có tên và được biên dịch trực tiếp trong Objective-C. Giao thức chính thức được sử dụng rộng rãi trong việc giao tiếp và trao đổi dữ liệu giữa các đối tượng khác nhau.
  • Giao thức không chính thức (Informal Protocol): Được triển khai thông qua category (danh mục mở rộng) thay vì khai báo chính thức bằng từ khóa @protocol. Các phương thức trong giao thức này không bắt buộc phải được các lớp triển khai, mang tính chất mở rộng tùy chọn.

Giải thích cách sử dụng các danh mục (category) trong Objective-C để mở rộng chức năng của các lớp hiện có

Danh mục trong Objective-C là một cơ chế cho phép mở rộng chức năng của một lớp đã tồn tại mà không cần phải sửa đổi trực tiếp mã nguồn của lớp đó.

Nhờ có danh mục, lập trình viên có thể thêm phương thức mới vào một lớp bất kỳ, kể cả lớp gốc của iOS như NSString, NSArray,… mà không cần phải tạo lớp con (subclass) hay thay đổi cấu trúc lớp ban đầu.

Cú pháp định nghĩa một category:

@interface MyClass (MyCategory)
- (void)newMethod;
@end

Cách triển khai:

@implementation MyClass (MyCategory)
- (void)newMethod {
    NSLog(@"New method from category!");
}
@end

Các kiểu id và Class của Objective-C khác nhau như thế nào và khi nào bạn sẽ sử dụng từng kiểu?

Trong Objective-C, idClass là hai kiểu dữ liệu đặc biệt, đều liên quan đến đối tượng, nhưng phục vụ những mục đích khác nhau. 

Tiêu chíKiểu idKiểu class
Định nghĩaĐại diện cho một con trỏ đến bất kỳ đối tượng nào trong Objective-CLà một con trỏ đến lớp (không phải đến một instance cụ thể)
Loại dữ liệuĐại diện cho instance của một lớpĐại diện cho bản thân lớp đó 
Thời điểm xác định kiểuKhông cần chỉ rõ lớp cụ thể của đối tượng tại thời điểm biên dịchPhải biết lớp (hoặc loại) tại thời điểm khai báo 
Tính linh hoạtRất linh hoạt, có thể dùng với bất kỳ đối tượng nàoHạn chế hơn, chỉ làm việc với lớp
Tình huống sử dụngKhi loại đối tượng chưa xác định hoặc không quan trọngKhi cần thao tác với lớp, như tạo đối tượng bằng alloc, gọi class method
Gọi phương thứcCó thể gọi bất kỳ phương thức nào, nhưng không được kiểm tra kiểu tại compile-timeDùng để gọi class methods (static methods)

Cho biết cách gọi các hàm/phương thức của Objective-C một cách bất đồng bộ?

Trong Objective-C, mỗi phương thức được nhận dạng bằng selector, gồm tên và vị trí tham số (dấu :). Selector trong Objective-C cho phép gọi phương thức động mà không cần biết tên hoặc kiểu của phương thức tại thời điểm biên dịch.

Đặc biệt hữu ích trong các tình huống cần xử lý linh hoạt, như khi làm việc với đối tượng không xác định hoặc từ một cấu hình ngoài.

Mục đích của @implementation trong Objective-C là gì và nó liên quan như thế nào đến @interface?

Trong Objective-C, @implementation được sử dụng để định nghĩa phần cài đặt thực tế cho các phương thức đã khai báo trong @interface. Cặp chỉ thị này giúp tách biệt phần khai báo và phần định nghĩa, làm cho mã nguồn rõ ràng và dễ bảo trì hơn.

Nếu @interface đóng vai trò như một bản thiết kế, nơi khai báo tên lớp, thuộc tính và các phương thức công khai, thì @implementation là nơi hiện thực hóa bản thiết kế đó bằng cách viết nội dung cụ thể cho từng phương thức.

Hãy giải thích cách hoạt động của PrintClassMethods để kiểm tra thời gian chạy trong Objective-C từ đoạn mã dưới đây

​​#import 
void PrintClassMethods(Class class) {
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList(class, &methodCount);
    for (unsigned int i = 0; i < methodCount; i++) {
        Method method = methods[i];
        SEL selector = method_getName(method);
        NSLog(@"Method: %@", NSStringFromSelector(selector));
    }
    free(methods);
}

​Trong đoạn code trên, PrintClassMethods sử dụng tính năng runtime introspection để liệt kê tất cả phương thức của một lớp được chỉ định. Nó lấy danh sách các phương thức và selector, cho phép lập trình viên kiểm tra và tương tác động với các phương thức của lớp tại thời gian chạy.

Giải thích ý nghĩa đoạn mã sau

#import 
@interface MyClass : NSObject
@end
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(dynamicMethod)) {
        class_addMethod(self, sel, (IMP)dynamicMethodIMP, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
void dynamicMethodIMP(id self, SEL _cmd) {
    NSLog(@"Dynamic method implementation.");
}
@end

Trong đoạn mã trên, phương thức resolveInstanceMethod: được ghi đè để thêm một phương thức mới tên là dynamicMethod khi chương trình đang chạy trong trường hợp phương thức này chưa được triển khai. Phần xử lý của dynamicMethod được định nghĩa trong hàm dynamicMethodIMP, nhờ đó lớp MyClass có thể đáp ứng và thực thi lời gọi đến dynamicMethod một cách linh hoạt và động.

Câu hỏi thực hành Objective-C 

Hãy viết một chương trình tính thể tích hộp

Viết một class Objective-C có tên Box với ba biến instance len, br, h và một property h. Class này có phương thức vol để tính thể tích của box bằng công thức len * br * h

Trong hàm main, tạo hai đối tượng Box, thiết lập chiều cao khác nhau cho mỗi box và in ra thể tích của từng box.

Code

#import <Foundation/Foundation.h>
@interface Box:NSObject {
   double len;    // Chiều dài
   double br;   // Chiều rộng
   double h;    // Chiều cao
}
@property(nonatomic, readwrite) double h;  // Property
-(double) vol;
@end
@implementation Box
@synthesize h; 
-(id)init {
   self = [super init];
   len = 4.0;
   br = 6.0;
   return self;
}
-(double) vol {
   return len*br*h;
}
@end
int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
   Box *box1 = [[Box alloc]init];    // Create box1 object of type Box
   Box *box2 = [[Box alloc]init];    // Create box2 object of type Box
   double vol = 0.0;             // Biến lưu trữ kích thước của box
   // box 1 specification
   box1.h = 5.0; 
   // box 2 specification
   box2.h = 10.0;
   // volume of box 1
   vol = [box1 vol];
   NSLog(@"Volume of Box1 : %f", vol);
   // volume of box 2
   vol = [box2 vol];
   NSLog(@"Volume of Box2 : %f", vol);
   [pool drain];
   return 0;
}

Output

Hãy tạo giao thức tùy chỉnh

Hãy viết một protocol Objective-C có tên MyProtocol với một phương thức doSomething

Sau đó, tạo một class MyClass kế thừa từ NSObject, tuân thủ (conform) giao thức MyProtocol và triển khai phương thức doSomething để in ra thông báo “Doing something…”.

// Creating blue print of the protocol
@protocol MyProtocol
// function in the protocol
- (void)doSomething;
@end
// Inherited MyClass from NSObject, with 
// the MyProtocol
@interface MyClass : NSObject <MyProtocol>
@end
// Implementing the MyClass class. 
@implementation MyClass
- (void)doSomething {
    NSLog(@"Doing something...");
}
@end

Hãy viết đoạn code hiển thị ngày và giờ theo định dạng

Hãy viết một chương trình Objective-C hiển thị ngày hiện tại theo định dạng yyyy-MM-dd. Chuyển đổi ngày này thành chuỗi, in ra chuỗi, sau đó chuyển ngược chuỗi thành đối tượng NSDate và in ra kết quả.

Code

// Objective-C program to display date and time in the specified format
#import <Foundation/Foundation.h>
int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   NSDate *date= [NSDate date];
   NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
   // Setting the format
   [dateFormatter setDateFormat:@"yyyy-MM-dd"];
   // Displaying the current format
   NSString *dateString = [dateFormatter stringFromDate:date];
   NSLog(@"Current date is %@",dateString);
    // Displaying the new format
   NSDate *newDate = [dateFormatter dateFromString:dateString];
   NSLog(@"NewDate: %@",newDate); 
   [pool drain];
   return 0;
}

Output:

Lưu ý: Trong NSDateFormatter, @"yyyy" biểu thị năm dương lịch thông thường, còn @"YYYY" biểu thị năm theo lịch tuần ISO (week-based year). Hai giá trị này có thể khác nhau vào thời điểm gần cuối năm hoặc đầu năm. Ví dụ, ngày 31/12/2023 có thể được định dạng thành “2024” nếu dùng @"YYYY" vì nó nằm trong tuần đầu tiên của năm 2024 theo chuẩn ISO. 

Trong đoạn code trên, ITviec đã sử dụng @"yyyy" để hiển thị đúng năm dương lịch!

Hãy viết một đoạn mã bằng cách sử dụng category

Hãy viết một chương trình Objective-C sử dụng category để mở rộng lớp NSString bằng cách thêm một phương thức mới có tên getnumber (class method) trả về chuỗi “Getting the number 111 and function is successfully executed”. Trong main, gọi phương thức này và in ra kết quả.

Code:

// Objective-C program for categories
#import <Foundation/Foundation.h>
// Creating category
@interface NSString(Mynumber)+(NSString *)getnumber;
@end
// Implementing the method
@implementation NSString(Mynumber) +(NSString *)getnumber 
{
   return @"Getting the number 111 and function is successfully executed";
}
@end
int main(int argc, const char * argv[]) 
{
   NSAutoreleasePool * temp = [[NSAutoreleasePool alloc] init];
   NSString *getnumber = [NSString getnumber];
   NSLog(@"output: %@",getnumber);
   [temp drain];
   return 0;
}

Output:

Getting the number 111 and function is successfully executed

Tổng kết

Như vậy, ITviec đã tổng hợp lại toàn bộ kiến thức về Objective-C, từ lý thuyết nền tảng đến các bài thực hành cơ bản và nâng cao. Những câu hỏi phỏng vấn Objective-C không chỉ nhằm đánh giá kỹ năng lập trình, mà còn là cơ hội để bạn hệ thống hóa kiến thức, hiểu sâu hơn về cách ngôn ngữ này vận hành và nâng cao sự tự tin khi bước vào môi trường làm việc. Hãy kiên trì luyện tập và không ngừng trau dồi để biến các câu hỏi này thành lợi thế trong hành trình chinh phục nhà tuyển dụng nhé!

Đọc chi tiết: Objective-C tutorial: 14 ngày tự học hiệu quả qua ví dụ thực tế 

TÁC GIẢ
Linh Trao
Linh Trao

Content Writer

Bắt đầu từ lúc còn là Sinh viên Báo chí - Truyền thông đến nay, Linh đã tích lũy hơn 8 năm kinh nghiệm trong chuyên môn viết lách. Với phương châm “chọn lọc đi kèm hiệu quả”, mỗi bài viết trên ITviec Linh đều đã “tối giản hóa” để người đọc dù là người mới bắt đầu hay IT có nhiều năm kinh nghiệm đều dễ tiếp cận, dễ hiểu và nhớ lâu. Linh chuyên sản xuất các bài viết thuộc chủ đề Front-End như CSS, TypeScript, JavaScript.