Lập trình · Ngôn ngữ lập trình
Hướng dẫn Objective-C cho người mới bắt đầu
Trả lời nhanh
Objective-C là C được bổ sung cơ chế truyền thông điệp hướng đối tượng theo kiểu Smalltalk. Bạn gọi phương thức bằng cách gửi thông điệp trong dấu ngoặc vuông, [object doSomething:arg], định nghĩa lớp trong các khối @interface và @implementation, và dùng framework Foundation của Apple cho chuỗi, mảng và từ điển. Đây từng là ngôn ngữ chính cho ứng dụng macOS và iOS trước Swift và vẫn được dùng trong nhiều cơ sở mã Apple hiện có. Trên Mac, biên dịch bằng clang -fobjc-arc -framework Foundation hello.m.
Objective-C là gì và ai dùng nó
Objective-C do Brad Cox và Tom Love tạo ra đầu thập niên 1980, được NeXT dùng cho hệ thống NeXTSTEP, rồi Apple kế thừa, khi NeXTSTEP trở thành nền tảng của macOS và iOS. Nó là tập cha chặt chẽ của C: mọi mã C đều là Objective-C hợp lệ và bạn có thể trộn hai thứ tự do.
Ngày nay Apple khuyến nghị Swift cho ứng dụng mới, nhưng Objective-C vẫn được hỗ trợ đầy đủ. Nó có trong các ứng dụng iOS và macOS cũ hơn, nhiều framework hệ thống và thư viện bên thứ ba, cùng các dự án trộn C hoặc C++ với API của Apple. Swift và Objective-C tương tác được trong cùng một dự án, nên biết cả hai rất hữu ích cho lập trình viên nền tảng Apple.
Cài đặt và chạy Hello, world
Trên macOS, cài Xcode hoặc chỉ các công cụ dòng lệnh (xcode-select --install), gồm trình biên dịch clang và framework Foundation. Tệp nguồn dùng phần mở rộng .m; tệp header dùng .h.
// hello.m
#import <Foundation/Foundation.h>
int main(void) {
@autoreleasepool {
NSLog(@"Hello, world!");
}
return 0;
}clang -fobjc-arc -framework Foundation hello.m -o hello
./hello
# 2026-10-31 10:00:00.000 hello[1234:5678] Hello, world!NSLog ghi ra lỗi chuẩn và thêm dấu thời gian cùng tên tiến trình. @"..." tạo một đối tượng NSString thay vì chuỗi C. -fobjc-arc bật Automatic Reference Counting, cách quản lý bộ nhớ chuẩn. Trên Linux, dự án GNUstep cung cấp thư viện Foundation tương thích, với lệnh build khác.
Kiểu, đối tượng và thông điệp
Vì Objective-C là C, mọi kiểu C đều dùng được. Đối tượng luôn được dùng qua con trỏ (NSString *name). Gọi phương thức được gọi là gửi thông điệp; các đối số xen kẽ với các phần của tên phương thức.
| Kiểu | Ví dụ | Ghi chú |
|---|---|---|
| Số của C | int, double, NSInteger | NSInteger là 64 bit trên nền tảng 64 bit |
| BOOL | BOOL ok = YES; | YES / NO |
| NSString * | @"hello" | Đối tượng chuỗi bất biến |
| NSNumber * | @42, @3.14, @(x + 1) | Đóng gói một số để collection có thể chứa nó |
| id | id thing = @"x"; | Con trỏ tới đối tượng bất kỳ, không có kiểu tĩnh |
| nil | nil | Con trỏ đối tượng rỗng |
NSString *name = @"Ana";
NSInteger age = 30;
NSString *line = [NSString stringWithFormat:@"%@ is %ld", name, (long)age];
NSLog(@"%@", line); // Ana is 30
NSLog(@"%lu", (unsigned long)[name length]); // 3
NSString *upper = [name uppercaseString]; // @"ANA"
BOOL same = [name isEqualToString:@"Ana"]; // YES
NSString *nothing = nil;
NSLog(@"%lu", (unsigned long)[nothing length]); // 0: messages to nil return 0Trong chuỗi định dạng, %@ in một đối tượng (gọi phương thức description của nó). Gửi thông điệp tới nil là được phép và trả về nil hoặc 0, tránh được nhiều vụ treo nhưng cũng có thể che giấu lỗi.
Luồng điều khiển
Luồng điều khiển y hệt C: if, else, switch, for, while và do ... while. Objective-C thêm duyệt nhanh bằng for ... in cho các collection.
NSInteger score = 85;
if (score >= 90) {
NSLog(@"A");
} else if (score >= 80) {
NSLog(@"B");
} else {
NSLog(@"C");
}
for (int i = 1; i <= 3; i++) {
NSLog(@"%d squared is %d", i, i * i);
}
for (NSString *fruit in @[@"apple", @"pear"]) {
NSLog(@"%@", fruit);
}Lớp, thuộc tính và phương thức
Một lớp có interface công khai (thường trong tệp .h) và phần triển khai (trong tệp .m). Phương thức thể hiện bắt đầu bằng -, phương thức lớp bằng +. @property khai báo một thuộc tính và tạo getter, setter cùng biến lưu trữ có tên bắt đầu bằng dấu gạch dưới.
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic) NSInteger age;
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;
- (NSString *)greeting;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
self = [super init];
if (self) {
_name = [name copy];
_age = age;
}
return self;
}
- (NSString *)greeting {
return [NSString stringWithFormat:@"Hi, I am %@, %ld", self.name, (long)self.age];
}
@end
// Usage inside main:
Person *ana = [[Person alloc] initWithName:@"Ana" age:30];
NSLog(@"%@", [ana greeting]); // Hi, I am Ana, 30
ana.age = 31; // dot syntax calls the setterĐối tượng được tạo qua hai bước: alloc cấp phát bộ nhớ và một phương thức init... khởi tạo nó. Phương thức ở trên có tên initWithName:age: (dấu hai chấm là một phần của tên). Protocol (@protocol) đóng vai trò interface, và category cho phép thêm phương thức vào lớp có sẵn, kể cả NSString.
Collection Foundation và block
Framework Foundation cung cấp các collection bất biến và các lớp con có thể thay đổi. Literal giúp viết chúng ngắn gọn. Collection chỉ chứa đối tượng, nên số được đóng gói thành NSNumber, và không thể lưu nil (hãy dùng [NSNull null]).
| Lớp | Literal hoặc cách tạo | Phiên bản có thể thay đổi |
|---|---|---|
| NSArray | @[@"Ana", @"Ben"] | NSMutableArray |
| NSDictionary | @{@"Ana": @30} | NSMutableDictionary |
| NSSet | [NSSet setWithArray:arr] | NSMutableSet |
| NSString | @"text" | NSMutableString |
NSArray<NSString *> *names = @[@"Ana", @"Ben"];
NSMutableArray<NSString *> *more = [names mutableCopy];
[more addObject:@"Cleo"];
NSDictionary<NSString *, NSNumber *> *ages = @{@"Ana": @30, @"Ben": @17};
NSLog(@"%lu names, Ana is %@", (unsigned long)more.count, ages[@"Ana"]);
NSInteger (^square)(NSInteger) = ^(NSInteger x) { return x * x; };
NSLog(@"%ld", (long)square(7)); // 49
NSArray<NSNumber *> *sorted = [@[@3, @1, @2]
sortedArrayUsingComparator:^NSComparisonResult(NSNumber *a, NSNumber *b) {
return [a compare:b];
}];
NSLog(@"%@", [sorted componentsJoinedByString:@", "]); // 1, 2, 3Block, viết bằng ^, là closure: hàm ẩn danh nắm bắt biến từ phạm vi xung quanh. API của Apple dùng chúng cho callback, sắp xếp và tác vụ bất đồng bộ với Grand Central Dispatch. Phần <NSString *> là generics nhẹ giúp trình biên dịch và Swift; chúng là tùy chọn.
Quản lý bộ nhớ và xử lý lỗi
Với ARC, trình biên dịch tự chèn các lời gọi đếm tham chiếu cho bạn: một đối tượng được giải phóng khi không còn tham chiếu mạnh nào trỏ tới nó. Bạn chỉ cần phá vỡ các chu trình tham chiếu, thường bằng cách đánh dấu một phía là weak (ví dụ thuộc tính delegate).
Lỗi có thể khắc phục dùng mẫu NSError: phương thức trả về nil hoặc NO khi thất bại và điền vào một đối tượng NSError truyền theo tham chiếu. Ngoại lệ (@try, @catch, NSException) có tồn tại, nhưng trong Cocoa chúng báo lỗi của lập trình viên như chỉ số ngoài phạm vi, không phải thất bại thông thường.
NSError *error = nil;
NSString *text = [NSString stringWithContentsOfFile:@"/no/such/file"
encoding:NSUTF8StringEncoding
error:&error];
if (text == nil) {
NSLog(@"Failed: %@", error.localizedDescription);
}Một chương trình hoàn chỉnh nhỏ: tần suất từ
#import <Foundation/Foundation.h>
int main(void) {
@autoreleasepool {
NSString *text = @"the cat and the hat and the bat";
NSMutableDictionary<NSString *, NSNumber *> *counts = [NSMutableDictionary dictionary];
for (NSString *word in [text componentsSeparatedByString:@" "]) {
counts[word] = @(counts[word].integerValue + 1);
}
NSArray<NSString *> *sorted = [counts keysSortedByValueUsingComparator:
^NSComparisonResult(NSNumber *a, NSNumber *b) { return [b compare:a]; }];
for (NSString *word in [sorted subarrayWithRange:NSMakeRange(0, 2)]) {
printf("%s %ld\n", word.UTF8String, (long)counts[word].integerValue);
}
}
return 0;
}
// the 3
// and 2Với từ mới, counts[word] là nil, và nil.integerValue trả về 0, nên số đếm đầu tiên thành 1. Bộ so sánh đảo thứ tự để sắp xếp theo số đếm từ cao xuống thấp, và printf in ra không có tiền tố của NSLog.
Học tiếp ở đâu
- Hướng dẫn "Programming with Objective-C" của Apple trong kho tài liệu để nắm kiến thức cơ bản về ngôn ngữ.
- Tài liệu tham khảo framework Foundation trong tài liệu dành cho nhà phát triển của Apple.
- Tài liệu Clang về Automatic Reference Counting để biết chính xác các quy tắc bộ nhớ.
- Tìm hiểu cách Objective-C và Swift làm việc cùng nhau nếu bạn bảo trì cơ sở mã hỗn hợp.
Câu hỏi thường gặp
Objective-C còn được dùng không?
Có, chủ yếu trong các ứng dụng và thư viện iOS, macOS hiện có. Apple khuyến nghị Swift cho mã mới, nhưng Xcode và các SDK của Apple vẫn hỗ trợ Objective-C.
Nên học Swift hay Objective-C trước?
Với phát triển Apple mới, hãy học Swift trước. Hãy học Objective-C khi bạn cần đọc hoặc bảo trì mã cũ, dùng sát các thư viện C hoặc C++, hoặc hiểu các framework của Apple hoạt động bên dưới ra sao.
Dấu ngoặc vuông trong Objective-C nghĩa là gì?
Chúng gửi một thông điệp: [receiver message] gọi phương thức message trên đối tượng receiver. Các đối số theo sau dấu hai chấm, như trong [dict setObject:value forKey:key].
Objective-C có thu gom rác không?
Objective-C hiện đại dùng Automatic Reference Counting (ARC), trong đó trình biên dịch thêm các lời gọi retain và release. Trình thu gom rác cũ của Apple cho macOS đã bị ngừng hỗ trợ và không còn nữa.