Check if key exists in NSDictionary is null or not

Check if key exists in NSDictionary is null or not
e.g:
NSDictionary *result;
UIImage *myImage = ([result objectForKey:@"image"] != [NSNull null] ? [result objectForKey:@"image"] : nil);
Labels:

Phần 6: Chuẩn bị “lên đỉnh” với iPhone application

Sau 5 bài học từ những cảm nhận “lần đầu” đến sự “vật lộn” với Objective-C, có lẽ các bạn cũng đã có trong tay một gia tài kha khá về lập trình Objective-C. Vậy đây có phải là mục tiêu cuối cùng của bạn chưa? Chúng tôi tin chắc rằng hầu hết các Apple developer đều mong muốn là có thể “lên đỉnh” với những ứng dụng cho iPhone, iPad do chính mình viết. Nếu quả thật như vậy thì các bạn sẽ còn cả một chặng đường dài phía trước. Tuy nhiên, để giúp các bạn có thể hoàn thiện về Objective-C cũng như có thêm những khái niêm liên quan đến iPhone development, chúng tôi xin giới thiệu thêm về Categories và Cocoa Touch (framework dùng để phát triển ứng dụng trên iOS).

Categories

Vì vậy, category là gì? Rất nhiều các hướng dẫn hay bài học về Objective-C thường không nhắc tới nó. Theo quan điểm của chúng tôi đó là một điều rất đáng tiếc bởi vì thực sự đó là một tính năng khá hữu ích. Category giúp giữ mã lệnh sáng sủa và ít lộn xộn bằng cách loại bỏ sự cần thiết cho việc khai báo các lớp con không cần thiết. Từ những gì chúng ta đã học được cho đến nay, nếu chúng ta có một đối tượng NSString và chúng ta muốn thêm một phương thức, ví dụ như để thay thế tất cả các ký tự ‘a’ với một ’4 ‘ thì chúng ta có thể tạo một lớp con của lớp NSString và thêm phương thức đó vào. Chúng tôi cũng đã chỉ các cách để tạo lớp con và thêm các phương thức trong ví dụ làm việc với lớp Car. Tạo lớp con là một cách tiếp cận tốt và chúng tôi không nói là các bạn không nên dùng lớp con. Tuy nhiên, trong một số tình huống nhất định, category cung cấp một cách tiếp cận tốt hơn để thêm một số chức năng bổ sung cho một lớp.

Category cho phép chúng ta có thể thêm các phương thức vào một lớp đã tồn tại, do đó tất cả các đối tượng thể hiện của lớp đó trong chương trình sẽ có thêm các phương thức mới. Ví dụ, chúng ta có 100 đối tượng NSString trong chương trình, nhưng bạn muốn tạo một lớp con tùy chỉnh để từng NSString có thêm một phương thức mới (giả sử là reverseString). Với các category, chúng tôi chỉ đơn giản là có thể thêm các phương thức vào một lớp thuộc category cụ thể (do chúng ta tạo nên) và tất cả các thể hiện trên category đó sẽ được phép sử dụng phương thức mới đó. Cú pháp rõ ràng là hơi khác so với việc sử dụng lớp con và category không cho phép bạn sử dụng instance variables. Tuy nhiên, nó có thể overriding các method đã được đặt ra, nhưng điều này nên được thực hiện một cách thận trọng và chỉ làm khi thực sự cần thiết.

Syntax

Category khai báo giống như bình thường chỉ khác ở chỗ sau tên lớp ta sẽ cho thêm tên của category. Cụ thể ta sẽ tìm hiểu cú pháp tạo category trong interface và lớp thực thi. Khai báo trong interface sẽ như sau:

@interface ClassName(category)
// method declarations go here...
@end

Còn trong lớp thực thi sẽ là:

@implementation ClassName(category)
// method implementations go here...
@end
Triển khai ví dụ

Thực sự là dễ dàng và dễ hiểu có phải không? Vì vậy, chúng ta hãy xem ví dụ: thực hiện một phương thức đơn giản mà sẽ đảo ngược một chuỗi. Các bạn đừng quan tâm đến ý nghĩa của phương thức mà hãy quan tâm đến cách thức ta sử dụng category để sau này có thể áp dụng vào bài toán của chính mình. Cụ thể ở interface sẽ như sau:

@interface NSString(reverse)
-(NSString *)reverseString;
@end

Bây giờ chúng ta sẽ xây dựng lớp thực thi như sau:

@implementation NSString(reverse)
-(NSString *)reverseString{}
@end

Tiếp theo, chúng ta sẽ thêm một số mã lệnh đơn giản để đảo ngược chuỗi. Để đảo ngược chuỗi chúng ta cần một đối tượng chuỗi trung gian chứa chuỗi đảo ngược. Cách chúng tôi sẽ đảo ngược chuỗi là chỉ đơn giản lặp các ký tự trong chuỗi hiện có theo thứ tự đảo ngược và lưu các ký tự đó vào chuỗi tạm thời. Mã lệnh cho cách thức trên sẽ như sau:

nsstringreverse_interface

Phương pháp này khá đơn giản, chúng ta sẽ dùng vòng lặp duyệt các ký tự trong chuỗi. Chúng ta nối thêm các ký tự hiện tại bằng cách sử dụng stringWithFormat và ký tự nhận dạng (%c). Nếu tất cả diễn ra tốt đẹp thì sau đó tất cả các đối tượng NSString trong chương trình của chúng ta phải tuân theo category mới. Cụ thể, bây giờ tất cả các đối tượng của NSString của chúng ta sẽ có phương thức reverseString để đảo ngược chuỗi mà nó đang chứa.

Ta sẽ lưu mã lệnh trong các file interface và lớp thực thi vào các file với tên theo theo quy ước riêng. Cụ thể, hai file mà chúng tôi đã tạo ra được đặt tên: NSString+reverse.h (interface) và NSString+reverse.m (lớp thực thi). Đây là một quy ước đặt tên biến điển hình của kiểu lớp mà có thêm một category (‘+’, và tên của category). Tiếp tục chúng ta sẽ vào lớp main. m để xây dựng đoạn mã để kiểm tra xem quá trình tạo category vừa rồi cho ta kết qủa như thế nào. Các bạn chú ý phải import  file header vừa tạo vào đầu file main.m. Trong đoạn mã lệnh bên dưới, chúng ta có khởi tạo đối tượng NSString nhưng các bạn đừng nhầm là đó là đối tượng nguyên bản trong foundation framework mà đó là đối tượng NSString thuộc categoryreverse” mà chúng ta đã tạo ra và như vậy ta có thể kiểm tra phương thức reverseString. Cụ thể, nội dung sẽ như thế này:

reversedstring_main

Nếu tất cả các bước trên bạn đã thực hiện đúng thì còn chần chừ gì nữa. Hãy ấn ngày button “Run” và tận hưởng kết quả là một chuỗi đã được đảo ngược “txeT elpmaS” trên màn hình output.

Như bạn có thể thấy, category thực sự là khá hữu ích (đặc biệt là với chuỗi). Chúng có thể sử dụng trong bất kỳ chương trình nào, một trong những trường hợp phổ biến chúng tôi hay sử dụng là phương thức kiểm tra tính hợp lệ đối với dữ liệu. Bằng cách này, chúng ta có thể giữ tất cả phương thức kiểm tra tính hợp lệ của dữ liệu ở một chỗ và không phải sử dụng bất kỳ subclass phức tạp nào cả.

Chuẩn bị “lên đỉnh” với iPhone application

Có lẽ nhiều bạn đọc đến đây sẽ rất “máu” và mong muốn “vọc” vào viết iPhone application ngay. Tuy nhiên đừng vội, hãy chuẩn bị thật kỹ vì chúng ta còn có nhiều thời gian. Phần tiếp theo chúng tôi xin giới thiệu một số khái niệm về Cocoa framework, một thành phần rất quan trọng đối với các Apple developer. Phần này chúng tôi sẽ không đi sâu nói về Objective-C nữa mà tôi muốn giới thiệu qua cho các bạn những công cụ, hướng dẫn hay cụ thể là những API mà các bạn cần dùng trong quá trình phát triển các iPhone application sau này.

Xcode và iOS SDK

Để phát triển các ứng dụng trên iPhone hay iPad các bạn cần phải hiểu kỹ về hệ điều hành mà các thiết bị này đang sử dụng bạn. Đó chính là hệ điều hành iOS. Đối với “người mới”, chắc hẳn các bạn sẽ lo lắng làm thể nào có thể trải nghiệm iOS hay dùng công cụ gì để phát triển các ứng dụng trên iOS. Không phải lo lắng, Apple đã làm hết cho bạn rồi. Nếu bạn đã cài hệ điều hành MacOS X thì bạn có thể cài thêm các option về XcodeiOS SDK. Xcode là một bộ công cụ cực kỳ tuyệt vời giúp bạn có thể dễ dàng tạo, xây dựng, kiểm tra và chạy thử các ứng dụng cho iOS. Tuy nhiên bạn đừng quên bạn sẽ không thể giả lập hay sử dụng tất cả các tính năng như trên các thiết bị thật nếu thiếu iOS SDK. Bộ SDK này chứa đầy đủ các thư viện để phát triển ứng dụng cũng như công cụ giả lập thiết bị giúp bạn có  cái nhìn trực quan các ứng dụng chạy trên iPhone hay iPad. Một lời khuyên chân thành là “hãy đầu tư một máy tính của Apple để phát triển các ứng dụng cho Apple“.

ios_sdk
Cocoa Touch framework

Cocoa Touch framework chứa các thư viện, API và runtime giúp cho Apple developer có thể nhanh chóng xây dựng các ứng dụng trên iOSCocoa Touch framework được xây dựng tập trung vào giao diện cảm ứng và tối ưu hóa các ứng dụng trên iOS. Trong Cocoa Touch framework, thành phần UIKit cung cấp các công cụ cơ bản mà bạn cần để xây dựng các ứng dụng GUI và hướng sự kiện trong iOS. UIKit được xây dựng dựa trên cơ sở của Foundation framework - thành phần rất quan trọng cho phát triển ứng dụng trên hệ điều hành MacOS X – bao gồm cả xử lý tập tin, mạng, xây dựng chuỗi và nhiều tính năng khác nữa.

Giao diện duy nhất của iOS có nghĩa rằng Cocoa Touch dùng để tạo ra có GUI có thiết kế độc đáo để phù hợp chỉ cho các thiết bị chạy iOS. Sử dụng UIKit bạn có quyền truy cập vào các điều khiển giao diện cảm ứng đa chạm, nút bấm, và xem toàn màn hình trên iOS.

framework_layer_2x_details-e1364364410664

Cocoa Touch và Objective-C

Phần lớn Cocoa Touch được tạo bởi Objective-C, một ngôn ngữ OOP được biên dịch để chạy với tốc độ đáng kinh ngạc. Bởi vì Objective-C được xây dựng từ C nên sẽ rất dễ dàng để kết hợp C và cả C++ vào các ứng dụng Cocoa Touch của bạn.

Khi ứng dụng của bạn chạy, Objective C runtime khởi tạo các đối tượng dựa trên quá trình thi hành logic – không chỉ ra trong quá trình biên dịch. Ví dụ, một ứng dụng Objective-C chạy có thể tải một interface (một tập tin nib được tạo ra bởi Interface Builder), kết nối các đối tượng Cocoa trong interface vào mã lệnh ứng dụng của bạn, sau đó gọi đúng phương thức mỗi khi UI button được nhấn. Không cần thiết phải biên dịch lại.

Tổng kết toàn bộ các bài học

Đây không chỉ là phần tổng kết của bài hướng dẫn này mà còn là phần tổng kết của seri bài về các nguyên tắc cơ bản trong Objective-C. Kết thúc seri này, các bạn đã tìm hiểu được những chủ đề sau:


  • Nguyên tắc cơ bản của lập trình Objective-C
  • Nguyên tắc cơ bản của OOP
  • Lớp và tính thừa kế
  • Quản lý bộ nhớ
  • Thực hành xây dựng hoàn thiện một bài toán đơn giản
  • Một số mở rộng của Objective-C

Chúng tôi hy vọng loạt bài này sẽ thực sự có ích cho các bạn mong muốn chinh phục Apple application và chúng tôi khuyên các bạn nên đọc lại seri bài viết này thêm một vài lần nữa để có thể hiểu sâu hơn về Objective-C trước khi bắt tay vào phát triển các ứng dụng cho iPhone hay iPad.

Thách thức

Đến thời điểm này, chúng ta đã hoàn tất toàn các bài học nhưng thách thức là vô tận nhất là nếu bạn còn muốn “lên đỉnh” với iPhone application. Chúng tôi sẽ đánh giá cao các bạn nếu các bạn quyết định sẽ xây dựng một ứng dụng đầu tiên ngay sau seri bài này. Xin chúc các bạn thành công với Objective-CiPhone application.

Phần 5: “Vật lộn” với việc quản lý bộ nhớ trong Objective-C

Chào mừng bạn đến với bài 5 của loạt bài về Objective-C này. Trong bài này, chúng ta sẽ tìm hiểu việc quản lý bộ nhớ, một một phần rất quan trọng của Objective-C (và nhiều ngôn ngữ khác). Hầu hết các ngôn ngữ kịch bản (chẳng hạn như PHP) quản lý bộ nhớ một cách tự động, nhưng Objective-C đòi hỏi rằng chúng ta là cẩn thận với việc sử dụng bộ nhớ của chúng ta. Điều đó có nghĩa là ta phải biết cách tự tạo và giải phóng không gian cho các đối tượng mà chúng ta đang sử dụng.

Phương pháp

Trong Objective-C, có 2 phương pháp để quản lý bộ nhớ, thứ nhất là dùng reference và thứ hai là dùng garbage collection. Bạn cứ nghĩ đơn giản là 2 cách thức theo kiểu là tự làm hoặc tự động theo môi trường của Objective-C, cụ thể reference counting là chúng ta phải tự làm còn garbage collection là cơ chế tự động và tự động quản lý bộ nhớ trong chương trình của chúng ta. Một lưu ý quan trọng là garbage collection không hoạt động trên iPhone, đó là lý do tại sao chúng tôi sẽ không tập trung nhiều vào phương pháp này. Nếu bạn muốn phát triển chương trình dành cho MacOS, bạn có thể tham khảo thêm các tài liệu trên website dành cho Apple Developer.

Cú pháp (Syntax)

Có nhiều cách thức khác nhau để tạo ảnh hưởng tới việc quản lý bộ nhớ. Trước hết, khi bạn tạo một đối tượng bằng cách sử dụng phương thức “alloc” (tạo mới hoặc copy) thì thực chất là bạn đã cấp cho nó một ô nhớ có thể chứa một sự thể hiện cho đối tượng đó và bạn sẽ là người quản lý đối tượng đó. Điều này cũng đúng trong trường hợp bạn dùng phương thức “retain”. Sau khi bạn tạo đối tượng xong rồi nếu bạn gọi phương thức release, hoặc autorelease (sẽ nói thêm về điều này sau) của đối tượng đó, bạn không còn có quyền quản lý đối tượng hoặc đảm nhiệm những công việc liên quan đến đối tượng đó nữa hay đơn giản là toàn bộ ô nhớ dành cho đối tượng đã khởi tạo sẽ bị giải phóng. Đoạn mã lệnh sau sẽ minh họa quá trình alloc một đối tượng:

Car *myCar = [Car alloc];

Sau khi chạy câu lệnh này thì chúng ta sẽ chịu trách nhiệm quản lý đối tượng myCar và tự xây dựng quá trình release (hoặc autorelease) đối tượng trong giai đoạn sau khi không cần sử dụng nó nữa. Điều quan trọng cần lưu ý rằng nếu bạn cố tình tiến hành thao tác release một đối tượng đã được thiết lập để autorelease thì ứng dụng ứng dụng của bạn sẽ lỗi.

Khi chúng ta tạo ra một đối tượng bằng cách sử dụng phương thức alloc, đối tượng xe của chúng ta sẽ có giá trị đếm là 1, có nghĩa là nó sẽ không được deallocate. Câu lệnh sẽ như sau:

[myCar retain];

Sau đó, khi có đối tượng mới được tạo, giá trị đếm của chúng ta sẽ tăng lên là 2 còn khi một trong những đối tượng được tạo không còn tồn tại nữa thì giá trị đếm lại giảm đi 1. Chỉ cho đến khi giá trị đếm đó về thành 0 thì đối tượng car mới được deallocate.

Khối lệnh autorelease

Khi bạn đã tạo ra một project mới trong Xcode, bạn có thể nhận thấy một số đoạn mã lệnh xuất hiện theo mặc định ví dụ như khối autorelease. Từ những bài trước chúng ta đã gặp nhưng tạm thời bỏ qua và bây giờ là thời điểm ta sẽ tìm hiểu cụ thể xem khối lệnh đó làm gì? Dưới đây là khối lệnh mặc định được thêm vào file main.m:autorelease

hoặc bạn có thể chủ động xây dựng kịch bản cho autorealease như sau:

  • NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [pool drain];

  • Trong đoạn mã trên ta sẽ thấy khi cần tạo ra khối lệnh xử lý autorelease thì ở trong câu lệnh thứ nhất chúng ta sẽ tạo một đối tượng từ lớp NSAutoReleasePool tên là pool và và câu lệnh thứ 2 sẽ kết thúc khối lệnh xử lý autorealse với lời gọi phương thức drain của đối tượng pool. Các câu lệnh mà khai báo trong phạm vi của 2 câu lệnh trên sẽ chịu ảnh hưởng của quá trình autorelease và cụ thể là chúng ta sẽ thấy nếu như các đối tượng được khởi tạo trong phạm vi này nếu như mà không còn có tham chiếu đến nó nữa thì nó sẽ tự động được release ra khỏi bộ nhớ mà chúng ta không cần phải tự viết thao tác release cho từng đối tượng.

    Giá trị retainCount

    Trước khi chúng tôi kết thúc, chúng ta hãy nhìn vào một cái gì đó mà có thể giúp làm cho bộ nhớ một chương quản lý dễ dàng hơn. Cho đến bài này chúng tôi đã tạo ra đối tượng và chúng tôi cũng biết có bao nhiêu bản thể hiện của đối tượng một đối tượng, nhưng làm thế nào để chỉ ra con số cụ thể đó? Đơn giản thôi, trên đối tượng thể hiện của chúng ta có một thuộc tính là retainCount và việc còn lại là ta chỉ cần in giá trị đó ra.

    NSLog (@"retainCount for car object:% d", [myCar retainCount]);

    retainCount trả về một số nguyên, vì vậy chúng tôi sử dụng %d để hiển thị giá trị trong phần định dạng.

    Tổng kết

    Thực sự việc quản lý bộ nhớ đối với hầu hết các ngôn ngữ đều là những vấn đề khá hóc búa. Một bài học chưa thể hướng dẫn chi tiết mọi vấn đề liên quan đến quản lý bộ nhớ. Vì vậy, chúng tôi có lời khuyên với những bạn mới học nên tạm cứ sử dụng những cơ chế tự động có sẵn trong Objective-C và khi đã có kinh nghiệm thì chúng ta sẽ đọc thêm tài liệu để tìm hiểu kỹ hơn về vấn đề này.

    Đến đây là kết thúc bài học thứ 5 và để có thể tìm hiểu thêm một số chức năng mở rộng của những lớp thuộc framework Cocoa Touch (giúp cho các bạn muốn phát triển ứng dụng trên iPhone sau này) xin mời các bạn đọc bài học cuối cùng trong seri này

    Phần 4: Xây dựng một chương trình Objective-C hoàn thiện

    Chào mừng bạn đến với bài học thứ 4 của loạt bài về Objective-C. Qua 3 bài học, chắc hẳn các bạn đã có những khái niệm cơ bản nhất về OOP trong Objective-C. Tiếp tục trong bài này, chúng tôi sẽ hướng dẫn các bạn xây dựng một chương trình hoàn thiện dựa trên những đối tượng bạn đã sử dụng ở bài học thứ 2.

    Bắt đầu

    Chúng ta sẽ bắt đầu với Xcode và tạo ra một project mới thông qua các các bước File> New Project> Mac OS X> Application> Command Line Tool, tiếp tục đặt tên project là “TestCar” và chọn Type: Foundation.

    new_project

    testcar_project

    Cuối cùng bạn nhấn vào nút Create để lưu project “TestCar” vào một chỗ cố định trong ổ cứng của bạn. Khi cửa sổ project xuất hiện bên tay trái, chúng ta sẽ cần phải tạo một lớp mới. Để làm được điều ày, bạn cần phải ấn tổ hợp phím Command-N (hoặc vào File> New File), sau đó chọn MacOS X> Cocoa> Objective-C class. Chúng ta sẽ đặt tên cho Class là “Car” và để mặc định tùy chọn Subclass of là NSObject (có nghĩa là lớp Car ta tạo ra sẽ là lớp con của NSObject). Cuối cùng nhấn button Create để lưu class Car vào thư mục của project TestCar.

    car_class

    Lớp Car bây giờ đã tạo ra nhưng nó không làm gì cả. Chúng ta sẽ thêm nội dung cho lớp Car. Tuy nhiên hãy ghi nhớ ở bài 2 chúng tôi đã có nói, Objective-C phân chia riêng biệt mã lệnh tạo một class thành 2 phần: một phần chứa các khai báo thuộc tính và phương thức là interface (file Car.h) và phần còn lại chứa phần lớp thực thi (file Car.m). Chúng ta sẽ tiến hành xây dựng interface trước tiên.

    Xây dựng Interface

    Chúng ta sẽ mở file Car.h và trong trạng thái ban đầu, nó sẽ giống ở trạng thái rỗng, có nghĩa là nội dung trong interface chưa có gì cả.

    empty_car_interface

    Trước hết, chúng ta phải khai báo foundation framework để có thể sử dụng được những lớp như NSString, NSMutableString… Sau đó, chúng ta sẽ tạo ra lớp Car là lớp con của NSObject. Trên lớp Car, chúng ta sẽ tạo ra một số thông tin lữu trữ những đặc tính của đối tượng Car. Cụ thể là đối tượng xe hơi thường sẽ có những thông tin như sau:

    • Make
    • Model
    • VIN

    Thực tế thì một chiếc ôtô sẽ có rất nhiều thuộc tính. Tuy nhiên ở đây chúng tôi chỉ xin đề ra 3 thuộc tính rất thông dụng mà mọi ôtô đều có. Đó là thuộc tính make chứa thông tin về hãng xe, model chứa thông tin về mẫu xe và VIN (Vehicle dentification Number).  Như vậy ở trên interface Car ta sẽ khai báo 3 thuộc tính sau dòng khai báo interface và nằm trong ngoặc {} như đoạn mã bên dưới:

    car_interface_with_attributes

    Tuy nhiên để bên ngoài có thể truy xuất giá trị của các thuộc tính thuộc trong lớp Car thì trên interface Car ta phải tạo ra các phương thức set... nhằm có thể thay đổi giá trị thuộc tính và các phương thức get... nhằm lấy các giá trị thuộc tính của một đối tượng Car đã khởi tạo.

    car_interface_with_get_set_methods

    Ngoài những phương thức get...set... chúng ta có thể tạo thêm cho lớp Car một số phương thức hoạt động khác ví dụ như:

    • start
    • addGas
    • stop

    Các phương thức trên sẽ được khai báo trong interface và ở đây chúng tôi xin áp dụng kiểu trả về là void cho cả 3 phương thức. Như vậy nội dung mới của interface Car sẽ như sau:

    car_interface_with_attributes_and_methods
    Xây dựng lớp thực thi

    Vì vậy, bây giờ sau khi ta đã khai báo các thuộc tính và phương thức trên interface thì việc tiếp theo của chúng ta là phải khởi tạo nội dung cho các phương thức đã khai báo trong interface. Nhìn lại, chúng ta cần tạo 6 phương thức: setVin, setMake, setModelvin, make, model. Nội dung của file “Car.m” như sau:

    car_class_with_methods5

    Nếu như các bạn đã tìm hiểu qua về OOP thì đều biết, bất cứ lớp nào được tạo ra đều có constructor có sẵn mặc định (phương thức khởi tạo đối tượng). Lớp Car trong Objective-C cũng giống như vậy, cho nên ta không cần tạo constructor trong lớp Car thì vẫn khởi tạo đối tượng Car được. Tuy nhiên để đảm bảo mỗi đối tượng được khởi tạo sẽ có sẵn những thông tin như chúng ta mong muốn thì ta phải tự xây dựng lại constructor. Cụ thể ta sẽ thêm đoạn mã tạo constuctor như sau:

    car_class_with_constructor_and_methods

    Xây dựng lớp chính (file main.m)

    Xin chúc mừng! Nếu bạn đã hoàn tất các bước trên thì bước cuối cùng này sẽ giúp chúng ta kiểm tra lại kết quả mà ta đã xây dựng. Cụ thể trong bước này ta sẽ làm các công việc sau:

    • Khởi tạo đối tượng myCar (một thể hiện của lớp Car)
    • Set và get giá trị các thuộc tính của đối tượng myCar
    • Thực thi các phương thức start, addGasstop của đối tượng myCar

    Để làm được những điều trên các bạn hãy mở file main.m và gõ theo nội dung dưới đây:

    testcar_main

    Sau khi đã hoàn tất viết mã cho lớp main bạn có thể chạy chương trình bằng cách nhấn vào nút Run ở bên trên cửa sổ Project hoặc vào menu Product> Run. Nếu quá trình dịch thành công bạn sẽ nhìn thấy kết quả ở cửa sổ output bên dưới màn hình như sau:

    testcar_output

    Phần tiếp theo

    Bài học thứ 4 đã kết thúc với một chương trình trọn vẹn trong Objective-C. Tuy nhiên nếu các bạn thành thạo những kỹ thuật trong OOP thì chúng tôi khuyên các bạn nên đọc thêm sách và thực hành nhiều hơn nữa. Để tiếp tục hiểu sâu hơn về cơ chế cấp phát và quản lý bộ nhớ trong Objective-C.

    Phần 3: “Quan hệ” giữa các đối tượng trong Objective-C

    Bài trước chúng ta đã nắm được những khái niệm cơ bản về lập trình hướng đối tượng (OOP), đã phân biệt được cách thức tổ chức các đối tượng trong chương trình Objective-C (tách riêng tệp interface và tệp lớp khởi tạo dựa trên interface đó). Trong bài này, chúng ta sẽ tìm hiểu sâu hơn về việc khởi tạo các đối tượng và tính thừa kế.

    Con trỏ và khởi tạo đối tượng

    Giả sử chúng ta muốn làm việc với một chuỗi ký tự, cụ thể là các thao tác nhập giá trị và in giá trị của chuỗi đó lên màn hình. Vậy chúng ta sẽ phải làm thế nào? Đoạn mã dưới đây sẽ minh họa điều trên:

    pointer_initializing1

    Chương trình trên được tạo trong Xcode bằng cách vào File> New Project> Mac OS X> Application> Command Line> Type: Foundation (khá là đơn giản) và gõ nội dung của chương trình trên vào file main.m (lớp chạy chính của project).

    Tiếp theo chúng ta sẽ tìm hiểu cụ thể cấu trúc của một chương trình viết bằng Objective-C. Chương trình Objective-C được xây dựng theo kiểu OOP nên bao gồm nhiều lớp (file có đuôi là .m), trong đó không thể thiếu được một lớp chạy chính đó là main.m (file này mặc định được tạo sẵn trong project mới).

    Dòng đầu tiên của file main.m là dòng khai báo sử dụng các thư viện chứa các đối tượng có sẵn (API) trong Objective-C hoặc do ta tạo ra. Cụ thể ở ví dụ trên, chúng ta sẽ báo với compiler biết rằng trong chương trình sẽ sử dụng các API cơ bản của foundation framework (foundation.h)

    #import <Foundation/Foundation.h>

    Để làm việc với một xâu ký tự chúng ta phải tạo ra một con trỏ đến một đối tượng NSString (tham khảo bài 2) gọi là testString. Câu lệnh đầu tiên chỉ là câu lệnh khai báo biến con trỏ tham chiếu đến chuỗi ký tự, thực sự thì chuỗi ký tự chưa được khởi tạo và chưa sẵn sàng để chứa các ký tự. Câu lệnh thứ 2, chúng ta mới khởi tạo tạo ra đối tượng cụ thể có thể chứa chuỗi ký tự.

    NSString *testString;
    testString = [[NSString alloc] init];

    Trên đây là cách viết tắt, còn cách viết đầy đủ thì câu lệnh thứ 2 ta sẽ phải tách làm 2 câu lệnh và cụ thể như sau:

    NSString *testString;
    testString = [NSString alloc];
    [testString init];

    Cách viết này có thể làm bạn bối rối vì đó là cách viết đầy đủ. Bạn có thể dùng theo cách viết ngắn gọn ở trên bằng cách lồng 2 ngoặc [] trên cùng một dòng lệnh. Tiếp tục sau khi đã khởi tạo thành công đối tượng xâu, chúng ta sẽ gán giá trị xâu cố định “Sample Text” cho nó. Cách thức thể hiện thao tác gán như sau:

    testString = @"Sample Text";

    Các bạn đã thấy, chúng tôi có thêm ký tự @ trước xâu ký tự là để báo với compiler biết rằng chuỗi văn bản sau @ là một NSString. Như vậy là đối tượng xâu đã có giá trị, vậy làm thế nào ta có thể in giá trị xâu đó ra màn hình? Ở đây ta sẽ không dùng những hàm IO của C mà chúng ta sẽ dùng một đối tượng có sẵn trong foundation framework. Đó là đối tượng NSLog với cú pháp như sau:

    NSLog(@"testString: %@", testString);

    Ở đây, đối tượng NSLog sẽ in một thông điệp ra màn hình console với cú pháp như trên. Phần trong nháy kép là giá trị xâu cố định và đi theo sau dấu @ và trong nháy kép là vị trí đặt giá trị của biến đối tượng xâu NSString đại diện với ký tự %@. Đó là quy định khi giá trị của một đối tượng xâu NSString ra màn hình console. Kết thúc phần nháy kép trong NSLog sẽ là là phần tiếp theo ngăn cách bởi dấu phẩy (,) chứa danh sách các biến con trỏ tham chiếu đến đối tượng chuỗi NSString, cụ thể mỗi một vị trí %@ sẽ in ra được một giá trị của một con trỏ xâu NSString theo đúng thứ tự. Để gỡ rối và chạy chương trình trong Xcode ta nhấn vào nút Run ở góc trái trên phần cửa sổ project và nhìn kết quả ở cửa sổ output bên dưới màn hình Xcode như hình bên dưới:

    teststring_output1

    Kết quả cuối cùng, chương trình sẽ trả về 0, điều này báo với hệ điều hành rằng mọi thao tác trong chương trình đã kết thúc và không có vấn đề bất thường gì cả.

    Thừa kế (Inheritance)

    Ở phần trên các bạn đã thấy cách chúng tôi thao tác với NSString. Có phải chúng tôi sử dụng các phương thức init? Đúng NSMutableString, NSArray và trong thực tế, bất cứ lớp NS nào cũng sử dụng phương thức init. Có vẻ ở đây chúng ta lãng phí rất nhiễu mã lệnh để đưa các phương thức init trong mỗi lớp, điều đó có đúng không? Thực sự là không phải vậy, trong OOP có một khải niệm đó là tính thừa kế (Inherinance), nó cung cấp cho ta một khả năng đó là khi có nhiều lớp có tính chất và hành động giống nhau thì ta sẽ tạo ra một lớp chứa các tính chất và hành động chung đó (lớp này gọi là lớp cha), sau đó các lớp con sẽ thừa kế tới lớp cha và có thể dùng lại các tính chất cũng như hành động của lớp cha mà không phải viết lại bất cứ dòng lệnh nào. Và thực tế là ở trong foundation framework, các lớp thư viện đều có chung một nguồn gốc, có nghĩa là tất cả các lớp đều thừa kế tới một lớp gốc, đó là lớp NSObject. Tất nhiên quá trình thừa kế này có thể tiếp tục để các lớp con cháu, chắt sẽ thừa kế lớp con của lớp cha. Tuy nhiên sự thừa kế ở đây là sự thừa kế đơn. Có nghĩa là một lớp con chỉ thừa kế một lớp cha mà thôi. Chúng ta sẽ nhìn vào sơ đồ bên dưới để thấy được sự phân câp quan hệ giữa một số lớp cơ bản trong foundation framework. Chúng tôi xin lưu ý rằng: việc nắm vứng sơ đồ qua hệ các class là hết sức quan trọng trong công việc lập trình của bạn sau này.

    inheritance

    Ở sơ đồ trên, các tác giả của Objective-C chỉ cần tạo trong NSObject một phương thức gọi là init và sau đó các lớp con sẽ thừa kế tới lớp NSObject để dùng lại phương thức init và để đảm bảo các đối tượng con sẽ được khởi tạo một cách đúng đắn giống nhau. Tuy nhiên trong quá trình thừa kế, các lớp con có thể ghi đè hay sửa đổi nội dung một số đặc tính hay phương thức của lớp cha. Đó gọi là thừa kế có cải tiến hay còn gọi là ghi đè phương thức (method overiding). Lý do của việc này theo phương pháp lập trình OOP khi các lớp con cùng thừa kế một lớp cha nhưng nó vẫn muốn đảm bảo tính đa dạng hay hay đa hình của các đối tượng con khi tạo ra có thể khác nhau chút xíu từ hình thức đến một số chi tiết hoạt động. Việc này hoàn toàn là hợp lệ và rất hiệu quả bời vì chúng ta hoàn toàn có thể tạo ra một lớp mới dựa trên những lớp đã có sẵn nhưng chúng ta cũng có thể thêm một số gia vị khác ở trên những lớp con đó và tạo nên sự đặc trưng riêng của những lớp do ta tạo nên. Việc này thực chất rất gần gũi với quan hệ giữa các đối tượng trong đời sống thực. Ví dụ bài toán quản lý phương tiện (Vehicle), tất cả các phương tiện sẽ đều có những tính chất chung giống nhau nên ta tạo ra một lớp vehicle đóng vai trò là lớp cha và sau đó ta sẽ tạo ra những lớp con như Car, Bus, Truck… sẽ có cùng chung đặc điểm của lớp vehicle nhưng lại có một số đặc điểm và hoạt động chi tiết khác nhau. Ví dụ sau sẽ minh họa lớp Bus thừa kế tới lớp Vehicle:

    class_inheritance

    Tổng kết

    Cho đến thời điềm này, chúng tôi chắc các bạn đã nắm được một số nguyên tắc cơ bản của OOP trong Objective-C. Để có thể kiểm tra những kiến thức mình đã học, xin mời các bạn trả lời một số câu hỏi sau:


    • Sự khác biệt giữa một lớp và một đối tượng là gì?
    • Tại sao chúng ta sử dụng các lớp?
    • Tại sao phải sử dụng tính thừa kế?

    Phần tiếp theo

    Để có thể xây dựng được những chương trình OOP chọn vẹn.

    Phần 2: “Khám phá” OOP trong Objective-C

    Kết thúc bài 1 các bạn đã nắm được một số nguyên tắc cơ bản của ngôn ngữ C cũng như Objective-C. Trong bài học thứ 2 này, chúng ta sẽ tập trung tìm hiểu: tại sao Objective-C lại trở thành một ngôn ngữ tuyệt vời trong việc phát triển phần mềm, đặc biệt là những phần mềm trên MacOS và iOS? Cụ thể, chúng ta sẽ thảo luận về các nguyên tắc cơ bản của lập trình hướng đối tượng và làm thế nào để tạo ra một lớp hay gửi các thông điệp cho các đối tượng khác nhau trong chương trình Objective-C.

    Lập trình hướng đối tượng (OOP)

    Tại sao chúng ta lại dùng Objective-C? Tại sao không chỉ sử dụng mỗi ngôn ngữ C? Đơn giản vì Objective-C là ngôn ngữ OOPOOP giờ là một phương pháp lập trình hiện đại với rất nhiều ưu thế để các LTV có thể sử dụng trong quá trình phát triển phần mềm. OOP là một mô hình lập trình mà cho phép các nhà phát triển phần mềm có thể suy nghĩ và lựa chọn cách thức thiết kế một phần mềm theo hướng các đối tượng (objects) và các thuộc tính (attributes) của nó mà không theo cách truyển thống là phân tích dựa trên các biến dữ liệu và chức năng. Nói một cách đơn giản là OOP tiếp cận một bài toán cụ thể dưới cách nhìn là các đối tượng chứ không nhìn cụ thể ngay các chức năng và dữ liệu. Cụ thể, OOP cố gắng để có được trừu tượng hóa dữ liệu (data abstraction), đóng gói (packaging), mô đun (modularity), đa hình (polymophism) và thừa kế (inheritance). Nếu mà đi sâu vào chủ đề của OOP thì chúng tôi cam đoan rằng nói cả ngày sẽ không hết. Cho nên chúng tôi xin giải thích đơn giản qua các ví dụ.

    Hãy tưởng tượng rằng bạn muốn mua một chiếc xe hơi (car) và bạn có thể nghĩ xe của bạn như một đối tượng. Có rất nhiều xe khác trên thế giới và thậm chí bạn có thể sở hữu nhiều hơn một. Hãy thử tưởng tượng xem chiếc xe hơi bạn định mua có những tính chất khác nhau như: mô hình, động cơ loại màu sắc, và nhiều hơn nữa. Về Lập trình hướng đối tượng, chúng ta gọi quá trình diễn tả này là trừu tượng hóa khái niệm một chiếc xe  thành một “lớp” (class) và khi bạn sở hữu thực sự một chiếc xe thì khi đó bạn sẽ đã có được một chiếc xe có với hình ảnh, chất liệu và máy móc thật và nó gọi là một sự thể hiện của (instantiated object) của lớp xe hơi (car class). Khi một chiếc xe khác mới được sản xuất và bán cho một khách hàng khác thì lại một sự thể hiện (instantiated object ) khác của lớp xe hơi (car class) được tạo ra.

    Vì vậy, tại sao chúng ta lại nghĩ theo hướng các đối tượng? Một trong những lý do tốt nhất là bởi vì đây là cách bộ não của bạn tự nhiên quan niệm cuộc sống trong thế giới thực. Trong đời sống thực, hầu hết các hệ thống nghiệp vụ hàng ngày ta thường quan niệm đó là sự tương tác của các đối tượng khác nhau. Vì vậy, chúng ta sẽ có rất nhiều lợi ích khi trừu tượng hóa sự phát triển phần mềm theo cách tương tự như những suy nghĩ trong đời sống thực.

    Phân biệt lớp (class) và đối tượng (object)

    Trong OOP, class là một tập hợp các dữ liệu đóng gói và phương pháp tùy chỉnh. Một lớp có thể tổ chức nhiều loại dữ liệu khác nhau, và các phương thức lớp thường (nhưng không phải luôn luôn) thực hiện hành động liên quan đến dữ liệu đó. Trong Objective-C, một lớp thường bao gồm hai tập tin: một file interface và một file thực thi. Các tập tin giao diện sử dụng phần mở rộng (.h). Theo quy ước interface là nơi mà LTV dùng để khai báo các phương thức và dữ liệu mô tả cho lớp đó. Các tập tin thực thi sử dụng phần mở rộng (.m) theo quy ước là nơi các mã thực thi thực sự sẽ được xây dựng và tất nhiên những mã đó sẽ ghi đè nên những khai báo về phương thức và thuộc tính dữ liệu trong file interface.

    Vậy, lớp khác đối tượng ở chỗ nào? Và đối tượng là gì? Thực tế, một đối tượng là một thể hiện của một lớp. Lớp giống như một khuôn mẫu chứa những khai báo về định dạng và nguyên tắc hoạt động và đối tượng được coi như một sản phẩm thực sự được tạo ra từ khuôn mẫu đó. Hãy nhớ lại ví dụ của chúng tôi ở trên với chiếc xe, cụ thể Car là một lớp với những tính chất chung và phương thức hoạt động chung của một cái xe. Tuy nhiên Car vẫn chỉ là ở trên giấy và chưa thành sản phẩm thực tế. Từ lớp Car nhà máy sẽ sản xuất và bán một chiếc xe cho Dans và chúng tôi gọi đó là đối tượng dansCar vì nó là đối tượng thực sự có thể hoạt động ngay được.

    Các class (dùng để khởi tạo các đối tượng – object) được tạo bởi các phương thức (methods) và các thuộc tính (abttributes). Nếu bạn đã làm quen với một ngôn ngữ không phải hướng đối tượng, bạn có thể là phải làm quen với một số khái niệm như: phương thức (methods) thì gần giống như với khái niệm chức năng (functions) và các thuộc tính (attributes) thì gần giống như với khái niệm các biến (variables). Tuy nhiên ở trong lập trình C thì dữ liệu và hàm ta có thể khai báo riêng biệt còn trong Objective-C thì dữ liệu và các phương thức hành động phải được đóng gói trong các class.

    Giới thiệu một số class được xây dựng sẵn trong Objective-C

    Chắc các bạn sẽ rất ngạc nhiên khi bắt tay vào viết mã lệnh trong Objective-C vì các đối tượng sẵn có trong foundation framework sao lại có chữ “NS” ở đằng trước. Tại sao lại thế? Phải chăng Apple cố ý tạo ra như thế để bắt các LTV phải viết thêm những câu lệnh dài dòng.

    Thực ra không phải là như vậy. Tất cả là do lịch sử. Các class trong foundation framework  của Apple được thêm vào phía trước chữ “NS”, đó là chữ viết tắt của NeXTSTEP. Khi Steve Jobs rời Apple, ông thành lập NeXT, tạo ra các máy tính trạm làm việc trên hệ điều hành của nó. Ngôn ngữ OOP được sử dụng để xây dựng hệ điều hành trên máy tính của NeXT có tên là NeXTSTEP (viết tắt là “NS”) và đó cũng là tên của hệ điều hành. Tuy nhiên do NeXTSTEP không được thương mại hóa nhiều nên ít người biết đến. Khi Apple mua lại NeXTSTEP, họ đã quyết định đổi tên ngôn ngữ đó thành Objective-C và xây dựng hệ điều hành MacOS X dựa trên NeXTSTEP.

    Dưới đây là một số class mà chúng ta hay sử dụng:

    NSLog: in ra màn hình console một xâu ký tự
    NSString: lớp chuỗi văn bản không thay đổi
    NSMutableString: lớp chuỗi văn bản có thể thay đổi
    NSArray: lớp mảng của các đối tượng không thay đổi
    NSMutableArray: lớp mảng của các đối tượng có thể thay đổi
    NSNumber: lớp chứa giá trị số…

    Phương thức (Methods)

    Như vậy, chúng ta đã có một “sự thể hiện” (instance) của một chiếc xe, bây giờ chúng ta phải làm gì với nó? Vâng, chúng tôi đổ xăng và khởi động xe và còn rất nhiều việc khác nữa như kiểm tra đèn, phanh… Đổ xăng và khởi động xe chỉ áp dụng cho những chiếc xe mà chúng tôi sở hữu và sử dụng. Điều đó có nghĩa rằng, 2 hành động trên chỉ tác động đến cái xe mà chúng tôi tương tác trực tiếp còn những cái xe khác trên thế giới sẽ không bị tác động và những cái xe đó lại bị tác động bởi người sở hữu và sử dụng chúng. Vì vậy, hành động đổ xăng và khởi động xe được coi như là các các phương thức được thể hiện (instance method) của các đối tượng thể hiện cụ thể (instantiated object). Và tất nhiên còn nhiều phương thức hoạt động của chiếc xe khác nữa mà ta có thể gọi ra, ví dụ: tiến, lùi, phanh, bật đèn, còi…, tuy nhiên chúng ta không thể gọi những hành động mà không được định nghĩa sẵn có trong xe hơi ví dụ như bay hoặc lặn. Tóm lại nếu ta là người sở hữu chiếc xe (chiếc xe đã được khởi tạo) thì chúng ta hoàn toàn có thể kiểm tra mọi thuộc tính cũng như các phương thức hoạt động của chiếc xe.

    Trong Objective-C, chúng ta gọi các phương thức của đối tượng bằng cách gởi thông điệp (passing messages). Ví dụ, khi chúng ta muốn biết có bao nhiêu khí trong bản thể hiện xe của chúng ta, chúng ta sẽ gửi một thông điệp tới bản thể hiện của chiếc xe (instance of car) và thông điệp đó chính là lời gọi một phương thức hoạt động (method) của bản thể hiện của chiếc xe mà ta muốn nó thực thi. Ví dụ như sau:

    [recipient message];

     

    Các dấu ngoặc vuông cho thấy chúng tôi đang gửi thông điệp. Tham số đầu tiên là đối tượng sẽ nhận được thông điệp này và tham số thứ hai là thông điệp đó thực sự là gì? Cụ thể là sẽ gọi tới phương thức nào của đối tượng được thể hiện “recipient”. Cuối cùng, chúng tôi kết thúc bằng một dấu chấm phẩy như là phổ biến với hầu hết các ngôn ngữ lập trình. Để rõ hơn ví dụ trên ta sẽ xem xét tiếp khi chiếc xe của Dans muốn thêm gas thì chúng ta sẽ làm gì?

    [dansCar addGas];

    Trong ví dụ trên này, ta giả sử chúng ta đã tạo ra một sự thể hiện của lớp xe hơi (car class) hay đơn giản hơn khi một khách hàng tên là Dans mua một chiếc xe và ta đặt tên cho nó là “dansCar”. Sau đó ta truyển tới đối tượng được thể hiện dansCar này một thông điệp tên là “addGas” hay ngắn gọi là yêu cầu đối tượng danCars thực thi phương thức hành động addGas và nó tương đương với gọi hàm addCars trong ngôn ngữ lập trình C hay Pascal.

    Thuộc tính (Attributes)

    Như các bạn đã biết, thực tế khi nhắc đến một đối tượng cụ thể thì ta thường hay nhớ đến những đặc điểm hay tính chất cụ thể của đối tượng của đối tượng đó. Giả sử khi nói đến một chiếc xe thì ta thường nhớ đến là chiếc xe của hãng nào, model nào hay như có mã số đăng ký là bao nhiêu? Chính bởi vậy, trong OOP, khi tạo ra các đối tượng để phản ánh trực tiếp các đối tượng trong cuộc sống hay trong một nghiệp vụ nào đó, chúng ta sẽ tạo ra một số thuộc tính để lưu trữ các giá trị mô tả đặc tính của một đối tượng. Tiếp tục với ví dụ đối tượng class Car ta sẽ tạo ra một số attributes như make, model hay vin. Các attributes đều được coi là các giá trị nội bộ có nghĩa là phạm vi truy suất nó chỉ ở trong đối tượng khởi tạo mà thôi. Thông thường để truy suất các attributes từ bên ngoài chúng ta thường tạo ra cặp phương thức get và set để thay đổi và lấy các giá trị của attribute đó.

    Câu lệnh sau giúp bạn có thể truy suất vào thuộc tính make của đối tượng thể hiện dansCar:

    [dansCar getMake];
    [dansCar make];

    Như ta đã thấy ở trên, toàn bộ methods và attributes được đóng gói trong class (encapsulation) và class sẽ quản lý methods và attributes. LTV sau này muốn sử dụng method hay attribute nào sẽ chỉ việc tham chiếu qua đối tượng thể hiện mà không phải quan tâm đến thực sự nội dung của chúng được tạo như thế nào. Tuy nhiên khi có nhiều các lớp có tính chất giống nhau và hành động giống nhau thì ta sẽ làm như thế nào?. Điều này chúng ta sẽ tìm hiểu kỹ ở phần tiếp theo.

    Interface và lớp khởi tạo (class)

    Theo mặc định, trong Xcode, khi bạn tạo một lớp Objective-C mới thì trong project của bạn sẽ có hai tập tin. Một là tập tin đại diện cho lớp thực thi với định dạng là (*.m) và tập tin của interface với đinh dạng là (*.h). Về nguyên tắc chung là lớp thực thi sẽ thừa kế các tính chất của interface mà nó import. Chính vì vậy ở trên interface ta sẽ định nghĩa những thuộc tính và những hành động chung đại diện cho một nhóm đối tượng. Sau đó ta sẽ tạo ra một đối tượng thừ kế tới interface và khởi tạo nội dung chi tiết của các phương thức hành động đã được định nghĩa trong interface.

    Giả sử ta sẽ tạo một project mới như sau: File> New Project> Mac OS X> Application> Command Line> Type: Foundation . Sau đó ta sẽ tạo một lớp Objective-C mới bằng cách vào File> New File> MacOS X> Cocoa> Objective-C class. Tiếp đó ta sẽ đặt tên lớp là Car với nội dung như sau:

    Car Interface (Car.h):

    interface

    Như trên, chúng ta đã khai báo rằng đây là interface Car, và trong dòng khai báo ta đặt thêm “: NSObject” có nghĩa là lớp Car do ta tạo sẽ thừa kế từ lớp NSObject (super class của mọi lớp trong Objective-C). Chúng tôi sẽ nói nhiều hơn về thừa kế trong những bài học tới. Trong interface Car ta khai báo các biến có tên là “make”, “model” và “vin” thực chất đây là là cá attribute của interface Car. Dòng tiếp theo có nghĩa trong interface Car có chứa một phương thức addGas. Tiền tố (void) ở trước có nghĩa là phương thức này không trả về bất cứ giá trị nào khi nó kết thúc thực hiện. Như thế chúng ta đã khai báo interface Car với thuộc tính và phương thức như trên, tất nhiên trong thực tế thì ta có thể thêm nhiều thuộc tính hay phương thức khác như: color, model, run, stop, break… Và như thế khi có bất cứ lớp thực thi nào thừa kế tới interface Car thì chúng đều có thuộc tính và method như trên.

    Car class (Car.m):

    class


    Như vậy là lớp thực thi Car.m là lớp khởi tạo dựa trên interface Car nên ta sẽ phải khởi tạo nội dung của tất cả các phương thức đã được khai báo ở interface Car. Cụ thể, để khởi tạo nội dụng cho phương thức addGas cho lớp Car.m, ta phải viết câu lệnh #import “Car.h” ở đầu file và xây dựng phần thân của phương thức addGas nằm trong dấu ngoặc {}. Khi khai báo phương thức addGas ta chú ý tiền tố -(void) có ý nghĩa là báo với compiler rằng method này sau khi chạy xong sẽ không trả về giá trị gì. Ở ví dụ trên, nội dung của phương thức đơn giản chỉ là một hành động in ra màn hình console một dòng chữ “Gas is added!”.

    Tuy nhiên để có thể truy suất các thuộc tính hay gọi một phương thức của 1 lớp thì điều trước tiên ta phải tạo một đối tượng thể hiện (instance of object) của lớp đó. Đoạn mã lệnh sau đây sẽ minh họa điều trên (chúng ta sẽ sử dụng lại việc định nghĩa lớp Car ở trên):

    Car *myCar = [[Car alloc] init];
    [myCar addGas];
    Phần tiếp theo

    Phần tiếp theo ta sẽ đi sâu hơn về OOP trong Objective-C và cụ thể là “quan hệ” giữa các đối tượng trong Objective-C.

    Phần 1: “Lần đầu” với lập trình Objective-C

    Chúng tôi rất vui vì các bạn đọc seri bài tự học Objective-C. Seri này gồm 6 bài viết rất chi là đơn giản giúp cho các bạn LTV dù chỉ có những kỹ năng lập trình cơ bản cũng sẽ dễ dàng hiểu Objective-C và nhanh chóng xây dựng được những chương trình đơn giản.  Đừng chần chừ gì nữa, chúng ta cùng bắt tay vào học ngay nào!

    Objective-C là gì?

    Nếu bạn đang đọc bài viết này thì tôi có thể chắc chắn gần như đến 99% là bạn đã có chút ít kinh nghiệm liên quan đến lập trình cũng như đã biết 1 vài ngôn ngữ lập trình thông dụng như C hay Java. Tuy nhiên nếu bạn là fresher hay beginner thì cũng chả sao bởi vì ai trong cuộc đời mà chả có “lần đầu”. Nào là “lần đầu tập đi”, “lần đầu tập nói”, lớn hơn một chút thì “lần đầu tập yêu” và rồi tiếp theo là “lần đầu lập trình”; đúng là “lần đầu” thì bỡ ngỡ thật nhưng từ lần sau chắc sẽ ổn hơn (chúng tôi hy vọng thế!!!). Tất cả điều chúng tôi mong đợi đó là “độ máu” của các bạn với MacOSObjective-C. Vậy Objective-C là gì? và nó có giống như C không?

    Objective-C là một ngôn ngữ lập trình hướng đối tượng (OOP) được xây dựng dựa trên ngôn ngữ lập trình C. Tuy nhiên ta phải thấy sự khác nhau giữa CObjective-C ở chỗ Objective-C là ngôn ngữ lập trình hướng đối tượng còn C lại là ngôn ngữ lập trình hướng thủ tục. Objective-C là ngôn ngữ chính được sử dụng để phát triển hệ điều hành MacOS X cũng như iOS (hệ điều hành chạy trên các thiết bị iPhone, iPod hay iPad). Thực chất, nó là ngôn ngữ được dùng để phát triển một hệ điều hành khác mà Apple đã mua về, NeXTSTEP, và hệ điều hành này đã trở thành một phần rất quan trọng giúp cho việc hình thành hệ điều hành chính thức MacOS của Apple sau này.

    Do Objective-C được phát triển từ C nên chúng ta có thể thoải mái sử dụng C trong chương trình viết bằng Objective-C và tất nhiên chương trình sẽ chạy ngon lành. Objective-C compiler sẽ chuyển tất cả mã lệnh viết bằng C sang thành mã biên dịch bằng Objective-C. Chính vì vậy mà Objective-C có đầy đủ sức mạnh của ngôn ngữ C và những cải tiến của một ngôn ngữ lập trình hướng đối tượng hiện đại.

    Nếu vẫn còn cảm thấy mơ hồ thì hay ghi nhớ câu thần chú như sau: tất cả những thứ C có thể làm được thì Objective-C cũng sẽ làm được, tuy nhiên chiều ngược lại chưa chắc đã đúng.

    Bạn cần phải chuẩn bị những gì để học Objective-C?

    Trong suốt chuỗi bài học này, chúng tôi sẽ không quá tập trung vào việc demo chi tiết quá trình phát triển các ứng dụng cho iPhone hay iPad. Thay vào đó, chúng tôi sẽ chú trọng tới ngôn ngữ Objective-C và chính bởi điều này mà tất cả ta cần chỉ là một máy tính Mac với một bộ compiler như GCC. Nếu bạn đã cài bộ công cụ phát triển cho Mac (Xcode) thì bạn hoàn toàn yên tâm là máy Mac của bạn đã có GCC complier và bạn có thể bắt tay ngay vào học Objective-C. Về mặt kinh nghiệm lập trình, chúng tôi cũng không bắt buộc bạn phải có quá nhiều kinh nghiệm về OOP hay đã rất thành thạo C. Tuy nhiên nếu bạn đã OK về hai vấn đề trên thì sẽ là một lợi thế lớn.

    Trong trường hợp bạn dùng Windows thì chúng tôi khuyên bạn nên dùng compiler khác như CygWin hay MinGW để dịch chương trình Objective-C. Tuy nhiên, chúng tôi khuyến cáo các bạn nên sử dụng hệ thống Mac vì như vậy bạn sẽ tận dụng được hết khả năng cũng như hiệu suất của ngôn ngữ Objective-C.

    Compile chương trình đầu tiên viết bằng Objective-C

    Giả sử bạn đã viết xong một chương trình bằng Objective-C, vậy làm thế nào bạn có thể dịch và chạy chương trình đó. Điều đầu tiên bạn phải sure là máy tình của mình có cài GCC compiler. Sau đó ta sẽ tiến hành dịch và chạy dòng lệnh chạy chương trình trên cửa sổ tương tác theo kiểu command line. Tất cả các ví dụ tôi demo trong chuỗi bài học này, chúng tôi đều chạy trên môi trường Mac và bạn hoàn toàn có thể thực thi các công việc liên quan đến khởi tạo và setup chương trình ban đầu thông qua công cụ mang tính trực quan hơn. Đó là bộ công cụ Xcode giúp bạn có thể dễ dàng phát triển những ứng dụng trên nền tảng Mac.

    Tuy nhiên điều bắt buộc đối với lập trình viên khi mới bắt đầu học ngôn ngữ lập trình là phải học cách chạy trên môi trường dòng lệnh thông qua command line. Công cụ chúng tôi sử dụng trên MacOSTerminal. Để chạy chương trình này bạn có thể vào Applications> Utilities> Terminal. Chương trình này giống chương trình cmd trong Windows.

    Bước 1: Trong cửa sổ Terminal, gõ lệnh

    cd /Users/MyName/Desktop/Test

    Lệnh cd giúp bạn có thể nhảy vào thư mục theo đường dẫn sau lệnh cd.

    Bước 2: Compile chương trình viết bằng Objective-C. Giả sử chương trình của bạn có tên là: inputfile.m (source file sẽ có đuôi là .m). Tiếp tục vẫn sử dụng cửa sổ Terminal, bạn gõ lệnh sau:

    gcc inputfile.m -o outputfile

    Kết thúc lệnh này sẽ GCC compiler sẽ dịch ra chương trình chạy có tên là outputfile.

    Bước 3: Để chạy chương trình, bạn chỉ cần gõ lệnh sau trên cửa sổ Terminal.

    ./outputfile

    Cơ bản về lập trình Objective-C

    Objective-C thực sự không quá khó để học. Khi bạn đã nắm vững những khái niệm và nguyên tắc lập trình cơ bản, bạn có thể tiếp tục tiến xa hơn nữa. Tuy nhiên bạn phải có những khải niệm căn bản về ngôn ngữ lập trình C. Và đó là phần còn lại trong buổi học hôm nay bởi vì những gì cơ bản của C cũng sẽ được sử dụng lại trong Objective-C.
    Chúng ta hãy nhìn vào chương trình cơ bản viết bằng C sau đây:

    hello_c_program

    Sau khi chạy chương trình ta sẽ thấy một thông điệp “Hello, World” trên cửa sổ Terminal.

    Bạn có thể bắt đầu việc tạo một chương trình Objective-C mới bằng cách khởi động Xcode, sau đó tạo project mới. Tiếp tục bạn chọn MacOS > Application> Terminal Command Tool. Chú ý bạn có thể chọn project type là C (nếu viết theo kiểu của C như ví dụ ở trên) hoặc là Foundation (nếu muốn viết theo kiểu Objective-C và sử dụng những đối tượng có sẵn trong foundation framework của Objective-C).

    Bạn thấy đó, chương trình Objective-C viết theo cú pháp của C nhìn rất quen thuộc có phải không? Điều duy nhất bạn phải làm là mau chóng recall lại những kiến thức cơ bản về C như các hàm IO hay khái niệm về biến.

    Biến (Variables)

    Phần tiếp theo ta sẽ tìm hiểu về biến. Biến được sử dụng cho mục đích lưu trữ các giá trị để chương trinh có thể thao tác trên các giá trị đó. Khi khai báo các biến ta phải chỉ ra tên của biến và kiểu dữ liệu của biến. Nói chung làm việc với các biến có kiểu dữ liệu cơ bản hoàn toàn giống với C. Một số kiểu dữ liệu cơ bản như sau:

    int – dùng để chứa các số nguyên
    char – dùng để chứa ký tự
    float – dùng để chứa các số có giá trị thập phân
    double – như kiểu float nhưng có phần thập phân chính xác hơn

    Ví dụ:
    variables


    Khi in giá trị của biến trên màn hình cửa sổ Terminal chúng ta phải chỉ ra định dạng giá trị cần in (bắt đầu bằng ký tự %). Chú ý một số định dạng thông dụng như sau:

    %i: int
    %f: float
    %e: double
    %c: char
    Câu lệnh điều kiện

    Khi một chương trình cần phải đưa ra quyết định lựa chọn các tình huống xử lý, chúng ta sẽ sử dụng một điều kiện. Nếu không có điều kiện, mỗi khi bạn chạy chương trình thì kết quả sẽ là giống hệt nhau (giống như ta xem đi xem lại một bộ phim nhiều lần). Bằng cách đưa ra những quyết định dựa trên điều kiện liên quan đến giá trị của các biến, chúng ta có thể thay đổi sự thực thi của chương trình – điều này gần giống như cuộc sống hàng ngày khi bạn lên một kế hoạch nào đó: nếu như thế này thì làm gì còn không thì làm gì?

    Cầu lệnh điều kiện đơn giản nhất là: câu lệnh if. Câu lệnh này sẽ xét xem nếu điều kiện trong câu lệnh if là true thì sẽ thực một thao tác cụ thể nào đó. Ví dụ:

    if_statement

    ngoài ra để xử lý điều kiện một cách tường minh và đầy đủ nhất ta có thể sử dụng cấu trúc lệnh if..else. Cấu trúc lệnh này cung cấp cho ta xử lý của cả 2 trường hợp: nếu điều kiện đúng thì làm gì và điều kiện sai thì làm gì.

    ifelse_statement


    Câu lệnh lặp

    Bây giờ ta tiếp tục tìm hiểu một trường hợp khác mà các chương trình rất hay gặp phải. Đó là khi một thao tác sẽ phải lặp đi lặp lại nhiều lần (tất nhiên ta phải kiểm soát được số lần lặp) thì lập trình viên cần dùng cấu trúc lệnh nào cho phù hợp? Trong trường hợp này chúng ta có thể dùng cấu trúc lệnh lặp để xử lý tình huống nêu trên.

    Có 3 loại vòng lặp thông dụng là: for, whiledo..while. Về mục đích thì cả 3 loại vòng lặp này đều có chung một nhiệm vụ là lặp đi lặp lại một đoạn mã n lần (cố gắng tránh vòng lặp vô tận) tuy nhiên cấu trúc của 3 lệnh này có khác nhau chút xíu.

    Vòng lặp for:

    for_statement

    Vòng lặp while:
    while_statement

    Vòng lặp do..while:
    dowhile_statement

    Con trỏ (pointer)

    Con trỏ là một khái niệm khá trừu tượng và rất khó của ngôn ngữ lập trình C. Do Objective-C dùng lại rất nhiều tính chất và kỹ thuật của C nên không quá ngạc nhiên ta gặp lại con trỏ ở trong Objective-C. Nếu bạn là fresher trong lĩnh vực lập trình thì chúng tôi khuyên bạn nên quay lại đọc kỹ phần con trỏ trong C để có thể có cái nhìn rõ ràng hơn về vấn đề này.

    Như các bạn đã đọc phần đầu thì ta đã biết khái niệm về biến. Biến dùng để lưu trữ giá trị cho mục đích tính toán và xử lý dữ liệu. Thực tế, khi ta tạo một biến có nghĩa là ta đã yêu cầu hệ thống cấp phát một ô nhớ nhằm lưu trữ giá trị của biến đó. Tất cả các thao tác liên quan đến dữ liệu trên ô nhớ đó ta sẽ thực hiện thông qua tên biến.

    Trong C, ta có thể thực hiện thao tác với dữ liệu trực tiếp trên ô nhớ thông qua con trỏ. Con trỏ là gì? Thực chất, con trỏ là một kiểu dữ liệu đặc biệt vì nó không lưu trữ những giá trị bình thường mà nó dùng để lưu địa chỉ của biến khác. Điều đó có nghĩa là ta có thể thao tác với dữ liệu trên một ô nhớ thông qua con trỏ đang nắm giữ địa chỉ của ô nhớ đó. Ví dụ:

    int foo = 123; // This is an integer variable
    int *ptr = &foo; // This is a pointer to an integer variable

    Phần tiếp theo
    Trên đây là nội dung của bài học đầu tiên. Chúng tôi hy vọng sau khi đọc bài này các bạn sẽ “vọc” vào làm luôn thông qua những hướng dẫn ở trên. Để tiếp tục “khám phá” OOP trong Objective-C
    2010 WEBSITE20. All rights reserved.