Objective-C: C với một tí Object
Objective-C
7
oop
15
White

Ngoc Dao viết ngày 22/03/2016

Bài này viết cuối năm 2008, khi Objective-C chưa có tính năng Automatic Reference Counting.

Objectish-C có lẽ là cái tên thích hợp hơn, vì Objective-C chỉ có một tí object và kém hơn những những ngôn ngữ hướng đối tượng phổ biến như Ruby, Java. Thế nhưng nếu không dùng Objective-C thì không tận dụng được tối đa lợi ích Apple cung cấp khi lập trình iPhone.

Bài viết này tóm tắt vài điều về Objective-C dành cho người đã biết C/C++, dùng khi mới bắt đầu làm quen với nó.

So sánh với C++

Cả Objective-C và C++ đều là mở rộng của C để thêm vào tính năng hướng đối tượng. Cả hai đều có "chuẩn" có tính năng tương tự như nhau. Nghĩa là chúng na ná như nhau cả. Điểm khác biệt sâu xa là ở triết lí: Objective-C hướng đến ngôn ngữ động, còn C++ thì ngược lại. Theo Wikipedia:

The use of reflection is part of the wider distinction between dynamic (run-time) features versus static (compile-time) features of a language. Although Objective-C and C++ each employ a mix of both features, Objective-C is decidedly geared toward run-time decisions while C++ is geared toward compile-time decisions. The tension between dynamic and static programming involves many of the classic trade-offs in computer science.

Khi tiếp cận Objective-C, tối thiểu nên học:

Quản lí bộ nhớ

Tùy platform mà Objective-C có (Mac OS X) hay không có (iPhone) tính năng giải phóng bộ nhớ tự động bằng garbage collector. Từ chỗ này trở đi chỉ nói về trường hợp không có garbage collector, lập trình viên phải tự giải phóng bộ nhớ.

Tuy phải tự phải tự giải phóng bộ nhớ, nhưng Objective-C có cách giúp bán tự động hoá. Ý tưởng là đối với từng object, sẽ đếm số lượng tham chiếu đến nó. Khi số lượng tham chiếu giảm xuống 0 thì bộ nhớ được tự động giải phóng:

  • Luôn dùng pointer để chứa object.
  • NSObject có sẵn tính năng đếm số tham chiếu (lưu vào biến retainCount). Tất cả class cần thừa kế từ class này hoặc class con của nó.

Các phương thức liên quan:

  • Cấp (retainCount = 1): alloc (class method).
  • Giữ tham chiếu vào biến nào đó (retainCount tăng 1): retain.
  • Copy thành biến khác (retainCount = 1): copy.
  • Giải phóng (retainCount giảm 1): release hoặc autorelease. Khi retainCount giảm xuống 0, dealloc được gọi để thực sự giải phóng bộ nhớ dùng để lưu object.
  • Khởi tạo: initXxx, khi viết phương thức này thường phía trên có [super initXxx], phía dưới có return self. Luôn phải gọi thủ công phương thức này.
  • Dọn dẹp: dealloc, khi viết phương thức này thường phía trên có [biến release], phía dưới có [super dealloc]. Đây là phương thức callback, không bao giờ gọi thủ công phương thức này. Khi retainCount giảm xuống 0 thì callback này được tự động gọi.
  • Khác nhau giữa dealloc và release/autorelease, theo forums.macumors.com:

Each object keeps a count of how many times it has been retained. Calling "release" reduces that count by one - it does not necessarily get rid of the object, if someone else has retained it. Dealloc is the real deal - the object will be destroyed. You should not, as far as I know, ever call dealloc (other than [super dealloc] at the end of your own dealloc method.) It will get called by "release" if no one else is retaining the object (When the count has gone to 0.)

  • Trong cùng phương thức, nếu phía trên alloc hay copy vào biến tạm dùng cục bộ, thì phía dưới phải release hay autorelease biến này. Ngược lại, chỉ release hay autorealse nếu phía trên alloc hay copy.
  • Đối với property, trong setter thì autorelease chứ không release, retain chứ không gán.

NSAutoreleasePool

Không muốn tự release cả đống object thì nhét chúng vào NSAutoreleasePool:

  • Trong initXxx, gọi autorelease ngay trước khi trả về self.
  • Kẹp lời gọi initXxx vào giữa dòng tạo pool và dòng drain pool.

Người mới bắt đầu làm quen với Objective-C thường thắc mắc tại sao thấy trong hàm main:

  • Phía trên có NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
  • Phía dưới có [pool release]
  • Nhưng ở giữa chẳng thấy dùng biến pool

Lí do là vì NSObject can thiệp. Nó giữ biến NSAutoreleasePool được init gần nhất để tự động sử dụng mỗi khi ở giữa gọi autorelease. Có 2 hệ quả:

  • Có thể lồng các khối NSAutoreleasePool vào nhau. Khi ta gọi autorelease thì Objective-C tự biết nhét biến vào NSAutoreleasePool mới nhất. Mỗi khi biến NSAutoreleasePool mới nhất được giải phóng, biến cũ hơn được tự động đôn lên thành biến mới nhất.
  • Khi chương trình sử dụng bộ nhớ nhiều, để tránh giữ bộ nhớ lâu mà không được tự động giải phóng, gây tình trạng thiếu bộ nhớ, làm cho chương trình ban đầu chạy nhanh nhưng càng chạy càng chậm, nên tạo NSAutoreleasePool mới mỗi khi cần thiết và giải phóng ngay pool sau khi dùng xong.

Ví dụ

Thử làm bài tập 4OOP:

Animal.h

#import <Foundation/NSObject.h>

@interface Animal:NSObject {
NSString *name;
}

- (Animal *) initWithName:(NSString *)aString;
- (void) setName:(NSString *)aString;
- (void) say;
@end

Animal.m

#import "Animal.h"

@implementation Animal
- (Animal *) initWithName:(NSString *)aString {
if (self = [super init]) {
[self setName:aString];
}
return self;
}

- (void) setName:(NSString *)aString {
[name autorelease];
name = [aString retain];
}

- (void) say {
NSLog(@"I am an animal, my name is %@.", name);
}

- (void) dealloc {
NSLog(@"Releasing %@", self);
[name release];
[super dealloc];
NSLog(@"Released");
}
@end

Cat.h

#import "Animal.h"

@interface Cat:Animal
- (void) say;
@end

Cat.m

#import "Cat.h"

@implementation Cat
- (void) say {
NSLog(@"I am a cat, my name is %@.", name);
}
@end

Zoo.h

#import "Animal.h"

@interface Zoo:NSObject {
NSMutableArray *animals;
}

- (Zoo *) init;
- (void) add:(Animal *)animal;
- (void) say;
@end

Zoo.m

#import "Zoo.h"

@implementation Zoo
- (Zoo *) init {
if (self = [super init]) {
animals = [[NSMutableArray alloc] init];
}
return self;
}

- (void) add:(Animal *)animal {
[animals addObject:animal];
}

- (void) say {
for (Animal *a in animals) {
[a say];
}
}

- (void) dealloc {
NSLog(@"Releasing %@", self);
[animals release];
[super dealloc];
NSLog(@"Released");
}
@end

main.m

#import "Animal.h"
#import "Cat.h"
#import "Zoo.h"

int main(int argc, const char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

Animal *animal = [[Animal alloc] initWithName:@"Animal"];
[animal autorelease];
Cat *cat = [[Cat alloc] initWithName:@"Kitty"];
[cat autorelease];
Zoo *zoo = [[Zoo alloc] init];
[zoo autorelease];
[zoo add:animal];
[zoo add:cat];
[zoo say];

[pool drain];
return 0;
}

Kết quả:

I am an animal, my name is Animal.
I am a cat, my name is Kitty.
Releasing <Zoo: 0x104fa0>
Released
Releasing <Cat: 0x104f30>
Released
Releasing <Animal: 0x1032d0>
Released

Tham khảo

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Ngoc Dao

102 bài viết.
283 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
62 8
Làm thế nào để nâng cấp trang web mà không làm gián đoạn dịch vụ? Đây là câu hỏi phỏng vấn các công ty lớn thường hỏi khi bạn xin vào vị trí làm lậ...
Ngoc Dao viết hơn 2 năm trước
62 8
White
40 1
Bài viết này giải thích sự khác khác nhau giữa hai ngành khoa học máy tính (computer science) và kĩ thuật phần mềm (software engineering), hi vọng ...
Ngoc Dao viết hơn 2 năm trước
40 1
White
34 1
Nếu là team leader, giám đốc công ty hay tướng chỉ huy quân đội, vấn đề cơ bản bạn gặp phải là “hướng mọi người đi theo con đường bạn chỉ ra”. Thử...
Ngoc Dao viết hơn 2 năm trước
34 1
Bài viết liên quan
White
0 0
Clojure là ngôn ngữ functional có hỗ trợ OOP. Về mặt khoa học máy tính, có nhiều cách để thực hiện đa hình. Ở phiên bản trước 1.2, đa hình trong Cl...
Ngoc Dao viết hơn 2 năm trước
0 0
White
2 1
Đó là: Chạy trong chế độ interactive Chạy trực tiếp bằng lệnh scala (chế độ thông dịch) Compile thành file .class rồi chạy như cách chạy của Jav...
Ngoc Dao viết hơn 2 năm trước
2 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
102 bài viết.
283 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!