Techmaster Việt Nam – Học là có việc

27 tháng 06, 2014 – 7055 lượt xem

Objective-C là ngôn ngữ lập trình chứa cả ngôn ngữ C. Điều này nghĩa là chúng ta có thể viết cả hai loại code trong cùng một file nguồn. Thật ra, hầu hết cấu trúc ngôn ngữ cốt  của Objective C là dựa vào C, chính vì thế ta cần phải có những kiến thức vững chắc về C trước khi đi sâu hơn.

Mô tả quan hệ của Objective-C và CMô tả quan hệ của Objective-C và C

Bài viết này sẽ cho bạn một cái nhìn tổng quát về lập trình C. Chúng ta sẽ nói về các chú thích, biến, toán tử, cấu trúc rẽ nhánh và lặp, cấu trúc dữ liệu đơn giản và vai trò tích hợp của con trỏ trong Objective C. Điều này sẽ cho ta kiến thức vững chắc để có thể tiếp tục với chức năng hướng đối tượng của Objective

Dòng chú thích

Có 2 cách để cho các chú thích vào trương trình C. Để có thể viết chú thích trên dòng (inline comment) thì cần hai gạch chéo ở trước và kết thúc tại dòng đó luôn. Chú thích theo dạng khối thì có thể trên nhiều dòng và cần phải viết trong /* và */. Ví dụ:

// This is an inline comment

/* This is a block comment.
   It can span multiple lines. */

Trình biên dịch hoàn toàn bỏ qua các dòng chú thích nên bạn có thể thêm vào các thông tin chú thích bên cạnh các dòng code. Điều này rất hữu ích khi cần giải thích các đoạn code phức tạp, khó hiểu; tuye nhiên, ngôn ngữ Objective C được thiết kế sao cho các dòng code rất dễ đọc dễ hiểu, nên bạn không thực sự cần phải thêm vào quá nhiều chú thích trong các ứng dụng iOS hay OS X

Các biến

Các biến có thể chứa nhiều giá trị khác nhau. Trong C, kiểu của biến là tĩnh, tức là bạn phải chỉ rõ một biến sẽ chứa giá trị kiểu nào. Để khai báo một biến, dùng cú pháp , và để gán một giá trị cho nó thì bạn dùng phép =.  Các biến là nơi có thể lưu giữ các giá trị khác nhau. Trong C, các biến phải được viết chi tiết, nghĩa là bạn phải viết hản ra lạ họ sẽ có những giá trị nào. Để có một biết, các bạn phải dùng cú phác và để đưa giá trị thì bạn cần = giá trị nào đó. Nếu bạn cần trình biên dịch hiểu một kiểu khác của biến, bạn có thể ép kiểu bằng cách thêm kiểu trong ngoặc tròn trước biến đó.

Tất cả những điều trên được chứng minh trong ví dụ sau đây. Ví dụ này khai báo một biến tên là odometer có thể mang giá trị kiểu double. Câu lệnh (int)odometer ép kiểu của giá trị trong odometer sang kiểu integer. Nếu bạn paste đoạn code này vào trong file main.m trong Xcode và chạy thử chương trình, bạn sẽ thấy dòng chữ NSLog() được hiển thị trong mục output

// main.m
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        double odometer = 9200.8;
        int odometerAsInteger = (int)odometer;
        
        NSLog(@"You've driven %.1f miles", odometer);        // 9200.8
        NSLog(@"You've driven %d miles", odometerAsInteger); // 9200
    }
    return 0;
}

Ngoài double và int, C còn định dạng đươc nhiều các loiaj giữ liệu khác bạn có thể tìm thấy tại phần Primitives, cũng như phần giải thích cho cú pháp %.1f và %d đã sử dụng ở trên

Hằng số

Có thể sử dụng từ khoá const để trình biên dịch biết rằng một biến không được phép thay đổi giá trị của nó. Ví dụ, định nghĩa một hằng số pi và thử thay đổi giá trị của nó, bạn sẽ gặp một lỗi biên dịch:

double const pi = 3.14159;
pi = 42001.0;               // Compiler error

Điều này thường được dùng trong các biến của hàm để thông báo cho người gọi hàm rằng họ có thể chắc chắn rằng giá trị được truyền vào sẽ không bị thay đổi.

Phép toán số học

Những kí hiệu quen thuộc +, -, *, / được dùng cho các phép toán số học cơ bản, và phép chia lấy số dư (%) có thể dùng để trả về số dư một phép chia hai số nguyên. Tất cả được biểu diễn dưới đây:

NSLog(@"6 + 2 = %d",  6 + 2);    // 8
NSLog(@"6 - 2 = %d",  6 - 2);    // 4
NSLog(@"6 * 2 = %d",  6 * 2);    // 12
NSLog(@"6 / 2 = %d",  6 / 2);    // 3
NSLog(@"6 %% 2 = %d", 6 % 2);    // 0

Cần thật cẩn thận khi thực hiện các phép toán với cả số thực dấu phẩy động và số nguyên. Xem thêm ở phần Chia số nguyên.

Bạn cũng sẽ thường xuyên gặp phép toán tăng (++) và giảm (–) trong cắc vòng lặp. Đây là các phép toán tiện ích đùng để tăng hoặc giảm 1 đơn vị. Ví dụ:

int i = 0;
NSLog(@"%d", i);    // 0
i++;
NSLog(@"%d", i);    // 1
i++;
NSLog(@"%d", i);    // 2

Cấu trúc điều kiện

C cung cấp cú pháp if tiêu chuẩn thường được thấy trong hầu hết các ngôn ngữ lập trình. Cú pháp của nó cùng với bảng biểu diễn những phép toán quan hệ/logic như sau:

int modelYear = 1990;
if (modelYear < 1967) {
    NSLog(@"That car is an antique!!!");
} else if (modelYear <= 1991) {
    NSLog(@"That car is a classic!");
} else if (modelYear == 2013) {
    NSLog(@"That's a brand new car!");
} else {
    NSLog(@"There's nothing special about that car.");
}

Phép toánMô tảa == bBằnga != bKhông bằnga > bLớn hơna >= bLớn hơn hoặc bằnga < bNhỏ hơna <= bNhỏ hơn hoặc bằng!aPhủ định logica && bLogic vàa || bLogic hoặc

C cũng có cú pháp switch, tuy nhiên chỉ nhận biến số nguyên, không nhận số thực, con trỏ hoặc đối tượng Objective-C. Điều này khiến nó không mềm dẻo bằng cú pháp if trước đó.

// Switch statements (only work with integral types) 
switch (modelYear) {
    case 1987:
        NSLog(@"Your car is from 1987.");
        break;
    case 1988:
        NSLog(@"Your car is from 1988.");
        break;
    case 1989:
    case 1990:
        NSLog(@"Your car is from 1989 or 1990.");
        break;
    default:
        NSLog(@"I have no idea when your car was made.");
        break;
}

Vòng lặp

Vòng lặp while và for được dùng để duyệt qua các giá trị, và các từ khoá liên quan như break hay continue cho phép bạn thoát khỏi vòng lặp hoàn toàn hoặc bỏ qua 1 vòng lặp.

int modelYear = 1990;
// While loops
int i = 0;
while (i<5) {
    if (i == 3) {
        NSLog(@"Aborting the while-loop");
        break;
    }
    NSLog(@"Current year: %d", modelYear + i);
    i++;
}
// For loops
for (int i=0; i<5; i++) {
    if (i == 3) {
        NSLog(@"Skipping a for-loop iteration");
        continue;
    }
    NSLog(@"Current year: %d", modelYear + i);
}

Mặc dù không phải là một phần của ngôn ngữ C, đây là lúc thích hợp để giới thiệu vòng lặp for-in. Đây là cú pháp duyệt-nhanh và là cách hiệu quả hơn để duyệt qua các tập hợp trong Objective-C như NSSet hay NSArray.

// For-in loops ("Fast-enumeration," specific to Objective-C)
NSArray *models = @[@"Ford", @"Honda", @"Nissan", @"Porsche"];
for (id model in models) {
    NSLog(@"%@", model);
}

Macros

Macros là một phương pháp bậc thấp để định nghĩa hằng số và là một cách viết tắt. Từ khoá #define trực tiếp ánh xạ một tên Macros với một đoạn code mở rộng là chuỗi các kí tự. Trước khi trình biên dịch bắt đầu dịch code, bộ tiền xử lý thay thế tất cả Macros xuất hiện trong code bằng đoạn code mở rộng của nó. Nói cách khác, Macros chính là một phương pháp tìm-kiếm-và-thay-thế

// main.m
#import <Foundation/Foundation.h>

#define PI 3.14159
#define RAD_TO_DEG(radians) (radians * (180.0 / PI))

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        double angle = PI / 2;              // 1.570795
        NSLog(@"%f", RAD_TO_DEG(angle));    // 90.0
    }
    return 0;
}

Đoạn code này biểu diễn hai loại Macros: macros kiểu đối tượng (PI) và macros kiểu hàm (RAD_TO_DEG(radians)). Điều khác biệt duy nhất là kiểu thứ hai thì chấp nhận biến đầu vào và truyền giá trị đó vào code mở rộng

Typedef

Từ khoá typedef cho phép bạn tạo ra những kiểu dữ liệu mới hoặc định nghĩa lại những kiểu đã có. Sau khi định nghĩa kiểu unsigned char trong đoạn code dưới đây, ta có thể sử dụng ColorComponent giống như sử dụng char, int, double hay bất kì kiểu nào khác:

// main.m
#import <Foundation/Foundation.h>

typedef unsigned char ColorComponent;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ColorComponent red = 255;
        ColorComponent green = 160;
        ColorComponent blue = 0;
        NSLog(@"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
              red, green, blue);
    }
    return 0;
}

Ngoài việc làm cho code sáng nghĩa hơn, typedef thường được sử dụng để chuyển struct và enum thành một kiểu dữ liệu. Điều này sẽ được giải thích trong phần tiếp theo.