Hướng dẫn nhanh Objective-C

Objective-C là ngôn ngữ đa năng được phát triển dựa trên ngôn ngữ lập trình C bằng cách bổ sung các tính năng của ngôn ngữ lập trình Small Talk khiến nó trở thành ngôn ngữ hướng đối tượng. Nó chủ yếu được sử dụng để phát triển hệ điều hành iOS và Mac OS X cũng như các ứng dụng của nó.

Ban đầu, Objective-C được NeXT phát triển cho hệ điều hành NeXTSTEP, từ đó nó được Apple tiếp quản cho iOS và Mac OS X.

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

Hỗ trợ đầy đủ lập trình hướng đối tượng, bao gồm bốn trụ cột của phát triển hướng đối tượng -

  • Encapsulation
  • Ẩn dữ liệu
  • Inheritance
  • Polymorphism

Mã mẫu

#import <Foundation/Foundation.h>

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

   NSLog (@"hello world");
   [pool drain];
   return 0;
}

Khung nền tảng

Foundation Framework cung cấp một loạt các tính năng và chúng được liệt kê bên dưới.

  • Nó bao gồm một danh sách các kiểu dữ liệu mở rộng như NSArray, NSDictionary, NSSet, v.v.

  • Nó bao gồm một tập hợp phong phú các hàm thao tác với tệp, chuỗi, v.v.

  • Nó cung cấp các tính năng để xử lý URL, các tiện ích như định dạng ngày tháng, xử lý dữ liệu, xử lý lỗi, v.v.

Mục tiêu học tập-C

Điều quan trọng nhất cần làm khi học Objective-C là tập trung vào các khái niệm và không bị lạc vào các chi tiết kỹ thuật ngôn ngữ.

Mục đích của việc học một ngôn ngữ lập trình là trở thành một lập trình viên giỏi hơn; nghĩa là, để trở nên hiệu quả hơn trong việc thiết kế và triển khai các hệ thống mới và bảo trì các hệ thống cũ.

Sử dụng Objective-C

Objective-C, như đã đề cập trước đó, được sử dụng trong iOS và Mac OS X. Nó có lượng lớn người dùng iOS và phần lớn người dùng Mac OS X. Và vì Apple tập trung vào chất lượng đầu tiên và điều tuyệt vời của nó đối với những người bắt đầu học Objective-C.

Thiết lập môi trường cục bộ

Nếu bạn vẫn sẵn sàng thiết lập môi trường của mình cho ngôn ngữ lập trình Objective-C, bạn cần hai phần mềm sau có sẵn trên máy tính của mình, (a) Trình soạn thảo văn bản và (b) Trình biên dịch GCC.

Trình soạn thảo văn bản

Điều này sẽ được sử dụng để nhập chương trình của bạn. Ví dụ về một số trình soạn thảo bao gồm Windows Notepad, lệnh Chỉnh sửa hệ điều hành, Tóm tắt, Epsilon, EMACS và vim hoặc vi.

Tên và phiên bản của trình soạn thảo văn bản có thể khác nhau trên các hệ điều hành khác nhau. Ví dụ: Notepad sẽ được sử dụng trên Windows và vim hoặc vi có thể được sử dụng trên windows cũng như Linux hoặc UNIX.

Các tệp bạn tạo bằng trình chỉnh sửa của mình được gọi là tệp nguồn và chứa mã nguồn chương trình. Các tệp nguồn cho các chương trình Objective-C thường được đặt tên với phần mở rộng ".m".

Trước khi bắt đầu lập trình, hãy đảm bảo rằng bạn đã có sẵn một trình soạn thảo văn bản và bạn có đủ kinh nghiệm để viết một chương trình máy tính, lưu nó vào một tệp, biên dịch và cuối cùng là thực thi nó.

Trình biên dịch GCC

Mã nguồn được viết trong tệp nguồn là nguồn con người có thể đọc được cho chương trình của bạn. Nó cần được "biên dịch" để chuyển thành ngôn ngữ máy, để CPU của bạn có thể thực thi chương trình theo hướng dẫn được đưa ra.

Trình biên dịch GCC này sẽ được sử dụng để biên dịch mã nguồn của bạn thành chương trình thực thi cuối cùng. Tôi giả sử bạn có kiến ​​thức cơ bản về trình biên dịch ngôn ngữ lập trình.

Trình biên dịch GCC có sẵn miễn phí trên các nền tảng khác nhau và quy trình thiết lập trên các nền tảng khác nhau được giải thích bên dưới.

Cài đặt trên UNIX / Linux

Bước đầu tiên là cài đặt gcc cùng với gói gcc Objective-C. Điều này được thực hiện bởi -

$ su - $ yum install gcc
$ yum install gcc-objc

Bước tiếp theo là thiết lập gói phụ thuộc bằng lệnh sau:

$ yum install make libpng libpng-devel libtiff libtiff-devel libobjc 
   libxml2 libxml2-devel libX11-devel libXt-devel libjpeg libjpeg-devel

Để có được đầy đủ các tính năng của Objective-C, hãy tải xuống và cài đặt GNUStep. Điều này có thể được thực hiện bằng cách tải xuống gói từhttp://main.gnustep.org/resources/downloads.php.

Bây giờ, chúng ta cần chuyển sang thư mục đã tải xuống và giải nén tệp bằng cách -

$ tar xvfz gnustep-startup-
      
       .tar.gz 
      

Bây giờ, chúng ta cần chuyển sang thư mục gnustep-startup được tạo bằng cách sử dụng -

$ cd gnustep-startup-<version>

Tiếp theo, chúng ta cần định cấu hình quá trình xây dựng -

$ ./configure

Sau đó, chúng ta có thể xây dựng bằng cách -

$ make

Cuối cùng chúng ta cần thiết lập môi trường bằng cách -

$ . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh

Chúng tôi có một mục tiêu helloWorld.m như sau:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   
   NSLog (@"hello world");
   [pool drain];
   return 0;
}

Bây giờ, chúng ta có thể biên dịch và chạy tệp Objective-C nói helloWorld.m bằng cách chuyển sang thư mục chứa tệp bằng cd và sau đó thực hiện theo các bước sau:

$ gcc `gnustep-config --objc-flags` 
-L/usr/GNUstep/Local/Library/Libraries 
-lgnustep-base helloWorld.m -o helloWorld
$ ./helloWorld

Chúng ta có thể thấy kết quả sau:

2013-09-07 10:48:39.772 tutorialsPoint[12906] hello world

Cài đặt trên Mac OS

Nếu bạn sử dụng Mac OS X, cách dễ nhất để lấy GCC là tải xuống môi trường phát triển Xcode từ trang web của Apple và làm theo hướng dẫn cài đặt đơn giản. Khi bạn đã thiết lập Xcode, bạn sẽ có thể sử dụng trình biên dịch GNU cho C / C ++.

Xcode hiện có sẵn tại developer.apple.com/technologies/tools/ .

Cài đặt trên Windows

Để chạy chương trình Objective-C trên windows, chúng ta cần cài đặt MinGW và GNUStep Core. Cả hai đều có sẵn tạihttps://www.gnu.org/software/gnustep/windows/installer.html.

Đầu tiên, chúng ta cần cài đặt gói Hệ thống MSYS / MinGW. Sau đó, chúng ta cần cài đặt gói GNUstep Core. Cả hai đều cung cấp một trình cài đặt windows, tự giải thích.

Sau đó, để sử dụng Objective-C và GNUstep bằng cách chọn Start -> All Programs -> GNUstep -> Shell

Chuyển sang thư mục chứa helloWorld.m

Chúng ta có thể biên dịch chương trình bằng cách sử dụng -

$ gcc `gnustep-config --objc-flags` 
-L /GNUstep/System/Library/Libraries hello.m -o hello -lgnustep-base -lobjc

Chúng ta có thể chạy chương trình bằng cách sử dụng -

./hello.exe

Chúng tôi nhận được kết quả sau:

2013-09-07 10:48:39.772 tutorialsPoint[1200] hello world

Trước khi nghiên cứu các khối xây dựng cơ bản của ngôn ngữ lập trình Objective-C, chúng ta hãy xem cấu trúc chương trình Objective-C tối thiểu để chúng ta có thể lấy nó làm tài liệu tham khảo trong các chương sắp tới.

Ví dụ về Objective-C Hello World

Về cơ bản, một chương trình Objective-C bao gồm các phần sau:

  • Lệnh tiền xử lý
  • Interface
  • Implementation
  • Method
  • Variables
  • Tuyên bố & Biểu thức
  • Comments

Chúng ta hãy xem một đoạn mã đơn giản có in dòng chữ "Hello World" -

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass

- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

@end

int main() {
   /* my first program in Objective-C */
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass sampleMethod];
   return 0;
}

Hãy để chúng tôi xem xét các phần khác nhau của chương trình trên -

  • Dòng đầu tiên của chương trình #import <Foundation / Foundation.h> là lệnh tiền xử lý, lệnh này yêu cầu trình biên dịch Objective-C bao gồm tệp Foundation.h trước khi chuyển sang biên dịch thực sự.

  • Dòng tiếp theo @interface SampleClass: NSObject hiển thị cách tạo giao diện. Nó kế thừa NSObject, là lớp cơ sở của tất cả các đối tượng.

  • Dòng tiếp theo - (void) sampleMethod; chỉ ra cách khai báo một phương thức.

  • Dòng tiếp theo @end đánh dấu sự kết thúc của giao diện.

  • Dòng tiếp theo @implementation SampleClass cho thấy cách triển khai giao diện SampleClass.

  • Dòng tiếp theo - (void) sampleMethod {} hiển thị việc triển khai sampleMethod.

  • Dòng tiếp theo @end đánh dấu sự kết thúc của quá trình triển khai.

  • Dòng tiếp theo int main () là hàm chính bắt đầu thực thi chương trình.

  • Dòng tiếp theo /*...*/ sẽ được trình biên dịch bỏ qua và nó đã được đưa vào để thêm các nhận xét bổ sung trong chương trình. Vì vậy những dòng như vậy được gọi là bình luận trong chương trình.

  • Dòng tiếp theo NSLog (...) là một hàm khác có sẵn trong Objective-C gây ra thông báo "Hello, World!" được hiển thị trên màn hình.

  • Dòng tiếp theo return 0; kết thúc hàm main () và trả về giá trị 0.

Biên dịch & Thực thi Chương trình Objective-C

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2017-10-06 07:48:32.020 demo[65832] Hello, World!

Bạn đã thấy cấu trúc cơ bản của chương trình Objective-C, vì vậy sẽ dễ dàng hiểu được các khối xây dựng cơ bản khác của ngôn ngữ lập trình Objective-C.

Mã thông báo trong Objective-C

Một chương trình Objective-C bao gồm các mã thông báo khác nhau và mã thông báo là một từ khóa, một mã định danh, một hằng số, một chuỗi ký tự hoặc một ký hiệu. Ví dụ: câu lệnh Objective-C sau đây bao gồm sáu mã thông báo:

NSLog(@"Hello, World! \n");

Các mã thông báo riêng lẻ là -

NSLog
@
(
   "Hello, World! \n"
)
;

Dấu chấm phẩy;

Trong chương trình Objective-C, dấu chấm phẩy là dấu chấm câu lệnh. Đó là, mỗi câu lệnh riêng lẻ phải được kết thúc bằng dấu chấm phẩy. Nó chỉ ra sự kết thúc của một thực thể logic.

Ví dụ, sau đây là hai câu lệnh khác nhau:

NSLog(@"Hello, World! \n");
return 0;

Bình luận

Nhận xét giống như văn bản trợ giúp trong chương trình Objective-C của bạn và chúng bị trình biên dịch bỏ qua. Chúng bắt đầu bằng / * và kết thúc bằng các ký tự * / như hình dưới đây -

/* my first program in Objective-C */

Bạn không thể có nhận xét với trong nhận xét và chúng không xảy ra trong một chuỗi hoặc ký tự.

Định danh

Số nhận dạng Objective-C là tên được sử dụng để xác định một biến, hàm hoặc bất kỳ mục nào khác do người dùng xác định. Số nhận dạng bắt đầu bằng chữ cái A đến Z hoặc từ a đến z hoặc dấu gạch dưới _ theo sau là không hoặc nhiều chữ cái, dấu gạch dưới và chữ số (0 đến 9).

Objective-C không cho phép các ký tự dấu câu như @, $ và% trong số nhận dạng. Objective-C là mộtcase-sensitivengôn ngữ lập trình. Như vậy, Nhân lựcnhân lực là hai định danh khác nhau trong Objective-C. Dưới đây là một số ví dụ về số nhận dạng được chấp nhận -

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

Từ khóa

Danh sách sau đây cho thấy một số từ dành riêng trong Objective-C. Những từ dành riêng này không được dùng làm hằng số hoặc biến hoặc bất kỳ tên định danh nào khác.

Tự động khác Dài công tắc điện
phá vỡ enum Đăng ký typedef
trường hợp bên ngoài trở về liên hiệp
char Phao nổi ngắn chưa ký
hăng sô cho đã ký vô hiệu
tiếp tục đi đến kích thước bay hơi
mặc định nếu tĩnh trong khi
làm int cấu trúc _Đóng gói
gấp đôi giao thức giao diện thực hiện
NSObject NSInteger NSNumber CGFloat
bất động sản giải phẫu học; giữ lại mạnh
Yếu không an toàn; đọc viết chỉ đọc

Khoảng trắng trong Objective-C

Một dòng chỉ chứa khoảng trắng, có thể có chú thích, được gọi là dòng trống và trình biên dịch Objective-C hoàn toàn bỏ qua nó.

Khoảng trắng là thuật ngữ được sử dụng trong Objective-C để mô tả khoảng trống, tab, ký tự dòng mới và nhận xét. Khoảng trắng phân tách một phần của câu lệnh với phần khác và cho phép trình biên dịch xác định vị trí một phần tử trong câu lệnh, chẳng hạn như int, kết thúc và phần tử tiếp theo bắt đầu. Do đó, trong câu lệnh sau:

int age;

Phải có ít nhất một ký tự khoảng trắng (thường là khoảng trắng) giữa int và age để trình biên dịch có thể phân biệt chúng. Mặt khác, trong câu lệnh sau,

fruit = apples + oranges;   // get the total fruit

Không cần ký tự khoảng trắng nào giữa trái cây và =, hoặc giữa = và táo, mặc dù bạn có thể thêm một số ký tự nếu muốn vì mục đích dễ đọc.

Trong ngôn ngữ lập trình Objective-C, kiểu dữ liệu đề cập đến một hệ thống mở rộng được sử dụng để khai báo các biến hoặc hàm thuộc các kiểu khác nhau. Kiểu của một biến xác định bao nhiêu không gian mà nó chiếm trong bộ nhớ và cách diễn giải mẫu bit được lưu trữ.

Các loại trong Objective-C có thể được phân loại như sau:

Sr.No. Loại & Mô tả
1

Basic Types −

Chúng là kiểu số học và bao gồm hai kiểu: (a) kiểu số nguyên và (b) kiểu dấu phẩy động.

2

Enumerated types −

Chúng lại là các kiểu số học và chúng được sử dụng để định nghĩa các biến chỉ có thể được gán các giá trị nguyên rời rạc nhất định trong suốt chương trình.

3

The type void −

Void xác định kiểu chỉ ra rằng không có giá trị nào.

4

Derived types −

Chúng bao gồm (a) Kiểu con trỏ, (b) Kiểu mảng, (c) Kiểu cấu trúc, (d) Kiểu liên kết và (e) Kiểu hàm.

Các kiểu mảng và kiểu cấu trúc được gọi chung là kiểu tổng hợp. Kiểu của một hàm chỉ định kiểu giá trị trả về của hàm. Chúng ta sẽ thấy các loại cơ bản trong phần sau trong khi các loại khác sẽ được đề cập trong các chương sắp tới.

Các loại số nguyên

Bảng sau cung cấp cho bạn thông tin chi tiết về các kiểu số nguyên tiêu chuẩn với kích thước lưu trữ và phạm vi giá trị của nó:

Kiểu Kích thước lưu trữ Phạm vi giá trị
char 1 byte -128 đến 127 hoặc 0 đến 255
ký tự không dấu 1 byte 0 đến 255
ký char 1 byte -128 đến 127
int 2 hoặc 4 byte -32,768 đến 32,767 hoặc -2,147,483,648 đến 2,147,483,647
int không dấu 2 hoặc 4 byte 0 đến 65,535 hoặc 0 đến 4,294,967,295
ngắn 2 byte -32,768 đến 32,767
không dấu ngắn 2 byte 0 đến 65,535
Dài 4 byte -2.147.483.648 đến 2.147.483.647
không ký lâu 4 byte 0 đến 4,294,967,295

Để có được kích thước chính xác của một loại hoặc một biến trên một nền tảng cụ thể, bạn có thể sử dụng sizeofnhà điều hành. Biểu thức sizeof (type) mang lại kích thước lưu trữ của đối tượng hoặc kiểu tính bằng byte. Sau đây là một ví dụ để lấy kích thước của kiểu int trên bất kỳ máy nào:

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Storage size for int : %d \n", sizeof(int));
   return 0;
}

Khi bạn biên dịch và thực thi chương trình trên, nó tạo ra kết quả sau trên Linux:

2013-09-07 22:21:39.155 demo[1340] Storage size for int : 4

Các loại dấu chấm động

Bảng sau cung cấp cho bạn thông tin chi tiết về các loại dấu phẩy động tiêu chuẩn với kích thước lưu trữ và phạm vi giá trị cũng như độ chính xác của chúng -

Kiểu Kích thước lưu trữ Phạm vi giá trị Độ chính xác
Phao nổi 4 byte 1,2E-38 đến 3,4E + 38 6 chữ số thập phân
gấp đôi 8 byte 2.3E-308 đến 1.7E + 308 15 chữ số thập phân
dài đôi 10 byte 3,4E-4932 đến 1,1E + 4932 19 chữ số thập phân

Tệp tiêu đề float.h xác định các macro cho phép bạn sử dụng các giá trị này và các chi tiết khác về biểu diễn nhị phân của số thực trong chương trình của bạn. Ví dụ sau sẽ in không gian lưu trữ được lấy bởi kiểu float và các giá trị phạm vi của nó:

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Storage size for float : %d \n", sizeof(float));
   return 0;
}

Khi bạn biên dịch và thực thi chương trình trên, nó tạo ra kết quả sau trên Linux:

2013-09-07 22:22:21.729 demo[3927] Storage size for float : 4

Loại trống

Loại void chỉ định rằng không có giá trị nào. Nó được sử dụng trong ba loại tình huống -

Sr.No. Các loại và Mô tả
1 Function returns as void

Có nhiều hàm khác nhau trong Objective-C không trả về giá trị hoặc bạn có thể nói chúng trả về giá trị vô hiệu. Một hàm không có giá trị trả về có kiểu trả về là void. Ví dụ,void exit (int status);

2 Function arguments as void

Có nhiều hàm khác nhau trong Objective-C không chấp nhận bất kỳ tham số nào. Một hàm không có tham số có thể chấp nhận là một khoảng trống. Ví dụ,int rand(void);

Bạn có thể chưa hiểu kiểu void vào lúc này, vì vậy hãy để chúng tôi tiếp tục và chúng tôi sẽ trình bày các khái niệm này trong các chương sắp tới.

Một biến không là gì ngoài tên được đặt cho một vùng lưu trữ mà chương trình của chúng ta có thể thao tác. Mỗi biến trong Objective-C có một kiểu cụ thể, xác định kích thước và cách bố trí bộ nhớ của biến; phạm vi giá trị có thể được lưu trữ trong bộ nhớ đó; và tập hợp các thao tác có thể áp dụng cho biến.

Tên của một biến có thể bao gồm các chữ cái, chữ số và ký tự gạch dưới. Nó phải bắt đầu bằng một chữ cái hoặc một dấu gạch dưới. Chữ hoa và chữ thường khác nhau vì Objective-C có phân biệt chữ hoa chữ thường. Dựa trên các kiểu cơ bản đã giải thích ở chương trước, sẽ có các kiểu biến cơ bản sau:

Sr.No. Loại & Mô tả
1

char

Điển hình là một octet đơn (một byte). Đây là một kiểu số nguyên.

2

int

Kích thước tự nhiên nhất của số nguyên cho máy.

3

float

Một giá trị dấu chấm động chính xác duy nhất.

4

double

Giá trị dấu phẩy động có độ chính xác kép.

5

void

Đại diện cho sự vắng mặt của loại.

Ngôn ngữ lập trình Objective-C cũng cho phép định nghĩa nhiều loại biến khác nhau mà chúng ta sẽ trình bày trong các chương tiếp theo như Enumeration, Pointer, Array, Structure, Union, v.v. Trong chương này, chúng ta hãy chỉ nghiên cứu các kiểu biến cơ bản.

Định nghĩa biến trong Objective-C

Định nghĩa biến có nghĩa là cho trình biên dịch biết vị trí và bao nhiêu để tạo bộ nhớ cho biến. Định nghĩa biến chỉ định một kiểu dữ liệu và chứa danh sách một hoặc nhiều biến của kiểu đó như sau:

type variable_list;

Đây, type phải là kiểu dữ liệu Objective-C hợp lệ bao gồm char, w_char, int, float, double, bool hoặc bất kỳ đối tượng nào do người dùng xác định, v.v., và variable_listcó thể bao gồm một hoặc nhiều tên định danh được phân tách bằng dấu phẩy. Một số khai báo hợp lệ được hiển thị ở đây -

int    i, j, k;
char   c, ch;
float  f, salary;
double d;

Dòng int i, j, k;cả khai báo và định nghĩa các biến i, j và k; hướng dẫn trình biên dịch tạo các biến có tên i, j và k kiểu int.

Các biến có thể được khởi tạo (gán giá trị ban đầu) trong khai báo của chúng. Bộ khởi tạo bao gồm một dấu bằng theo sau là một biểu thức hằng số như sau:

type variable_name = value;

Một số ví dụ là -

extern int d = 3, f = 5;    // declaration of d and f. 
int d = 3, f = 5;           // definition and initializing d and f. 
byte z = 22;                // definition and initializes z. 
char x = 'x';               // the variable x has the value 'x'.

Đối với định nghĩa không có bộ khởi tạo: các biến có thời lượng lưu trữ tĩnh được khởi tạo ngầm định với NULL (tất cả các byte đều có giá trị 0); giá trị ban đầu của tất cả các biến khác là không xác định.

Khai báo biến trong Objective-C

Một khai báo biến cung cấp sự đảm bảo cho trình biên dịch rằng có một biến tồn tại với kiểu và tên đã cho để trình biên dịch tiến hành biên dịch thêm mà không cần chi tiết đầy đủ về biến. Một khai báo biến chỉ có ý nghĩa tại thời điểm biên dịch, trình biên dịch cần khai báo biến thực tế tại thời điểm liên kết của chương trình.

Khai báo biến rất hữu ích khi bạn đang sử dụng nhiều tệp và bạn xác định biến của mình trong một trong các tệp, biến này sẽ khả dụng tại thời điểm liên kết chương trình. Bạn sẽ sử dụngexterntừ khóa để khai báo một biến tại bất kỳ vị trí nào. Mặc dù bạn có thể khai báo một biến nhiều lần trong chương trình Objective-C nhưng nó chỉ có thể được định nghĩa một lần trong một tệp, một hàm hoặc một khối mã.

Thí dụ

Hãy thử ví dụ sau, trong đó các biến đã được khai báo ở trên cùng, nhưng chúng đã được xác định và khởi tạo bên trong hàm chính:

#import <Foundation/Foundation.h>

// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {
  /* variable definition: */
  int a, b;
  int c;
  float f;
 
  /* actual initialization */
  a = 10;
  b = 20;
  
  c = a + b;
  NSLog(@"value of c : %d \n", c);

  f = 70.0/3.0;
  NSLog(@"value of f : %f \n", f);
 
  return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-07 22:43:31.695 demo[14019] value of c : 30 
2013-09-07 22:43:31.695 demo[14019] value of f : 23.333334

Khái niệm tương tự áp dụng cho khai báo hàm trong đó bạn cung cấp tên hàm tại thời điểm khai báo và định nghĩa thực tế của nó có thể được cung cấp ở bất kỳ nơi nào khác. Trong ví dụ sau, nó được giải thích bằng cách sử dụng hàm C và như bạn đã biết Objective-C cũng hỗ trợ các hàm kiểu C:

// function declaration
int func();

int main() {
   // function call
   int i = func();
}

// function definition
int func() {
   return 0;
}

Giá trị và giá trị trong Objective-C

Có hai loại biểu thức trong Objective-C -

  • lvalue- Các biểu thức tham chiếu đến một vị trí bộ nhớ được gọi là biểu thức "lvalue". Giá trị có thể xuất hiện ở dạng bên trái hoặc bên phải của bài tập.

  • rvalue- Thuật ngữ rvalue đề cập đến một giá trị dữ liệu được lưu trữ tại một số địa chỉ trong bộ nhớ. Giá trị là một biểu thức không thể có giá trị được gán cho nó, có nghĩa là giá trị có thể xuất hiện ở bên phải nhưng không xuất hiện ở bên trái của một phép gán.

Các biến là giá trị và do đó có thể xuất hiện ở phía bên trái của phép gán. Các chữ số là các giá trị và do đó, có thể không được gán và không thể xuất hiện ở phía bên trái. Sau đây là một tuyên bố hợp lệ -

int g = 20;

Nhưng sau đây không phải là một câu lệnh hợp lệ và sẽ tạo ra lỗi thời gian biên dịch -

10 = 20;

Các hằng số tham chiếu đến các giá trị cố định mà chương trình không thể thay đổi trong quá trình thực thi. Các giá trị cố định này còn được gọi làliterals.

Hằng số có thể thuộc bất kỳ kiểu dữ liệu cơ bản nào như hằng số nguyên, hằng số động, hằng ký tự hoặc chuỗi ký tự . Ngoài ra còn có các hằng số liệt kê.

Các constants được xử lý giống như các biến thông thường ngoại trừ việc không thể sửa đổi giá trị của chúng sau khi định nghĩa.

Chữ số nguyên

Một chữ số nguyên có thể là một hằng số thập phân, bát phân hoặc thập lục phân. Tiền tố chỉ định cơ số hoặc cơ số: 0x hoặc 0X cho hệ thập lục phân, 0 cho hệ bát phân và không có gì cho thập phân.

Một chữ số nguyên cũng có thể có một hậu tố là sự kết hợp của U và L, tương ứng là không dấu và dài. Hậu tố có thể là chữ hoa hoặc chữ thường và có thể theo bất kỳ thứ tự nào.

Dưới đây là một số ví dụ về các ký tự số nguyên -

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */
078         /* Illegal: 8 is not an octal digit */
032UU       /* Illegal: cannot repeat a suffix */

Sau đây là các ví dụ khác về các loại ký tự Số nguyên khác nhau -

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

Ký tự dấu phẩy động

Một ký tự dấu phẩy động có một phần nguyên, một dấu thập phân, một phần thập phân và một phần mũ. Bạn có thể biểu diễn các ký tự dấu phẩy động ở dạng thập phân hoặc dạng hàm mũ.

Trong khi biểu diễn bằng cách sử dụng dạng thập phân, bạn phải bao gồm dấu thập phân, số mũ hoặc cả hai và trong khi biểu diễn bằng cách sử dụng dạng mũ, bạn phải bao gồm phần nguyên, phần thập phân hoặc cả hai. Số mũ có dấu được giới thiệu bởi e hoặc E.

Dưới đây là một số ví dụ về các ký tự dấu phẩy động -

3.14159       /* Legal */
314159E-5L    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

Hằng số ký tự

Các ký tự ký tự được đặt trong dấu nháy đơn, ví dụ: 'x' và có thể được lưu trữ trong một biến đơn giản của char kiểu.

Một chữ ký tự có thể là một ký tự thuần túy (ví dụ: 'x'), một chuỗi thoát (ví dụ: '\ t') hoặc một ký tự phổ quát (ví dụ: '\ u02C0').

Có một số ký tự trong C khi chúng được tiếp tục bằng dấu gạch chéo ngược, chúng sẽ có ý nghĩa đặc biệt và chúng được sử dụng để biểu thị như dòng mới (\ n) hoặc tab (\ t). Tại đây, bạn có danh sách một số mã trình tự thoát như vậy -

Trình tự thoát Ý nghĩa
\\ \ tính cách
\ ' ' tính cách
\ " " tính cách
\? ? tính cách
\ a Cảnh báo hoặc chuông
\ b Backspace
\ f Thức ăn dạng
\ n Dòng mới
\ r Vận chuyển trở lại
\ t Tab ngang
\ v Tab dọc
\ ooo Số bát phân từ một đến ba chữ số
\ xhh. . . Số thập lục phân gồm một hoặc nhiều chữ số

Dưới đây là ví dụ để hiển thị một số ký tự thoát -

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Hello\tWorld\n\n");
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-07 22:17:17.923 demo[17871] Hello	World

Chuỗi ký tự

Các ký tự hoặc hằng số của chuỗi được đặt trong dấu ngoặc kép "". Một chuỗi chứa các ký tự tương tự như các ký tự: ký tự thuần túy, chuỗi thoát và ký tự phổ quát.

Bạn có thể ngắt một dòng dài thành nhiều dòng bằng cách sử dụng các ký tự chuỗi và phân tách chúng bằng cách sử dụng khoảng trắng.

Dưới đây là một số ví dụ về chuỗi ký tự. Tất cả ba hình thức là các chuỗi giống hệt nhau.

"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

Định nghĩa Hằng số

Có hai cách đơn giản trong C để xác định hằng số:

  • Sử dụng #define bộ tiền xử lý.

  • Sử dụng const từ khóa.

#Define Preprocessor

Sau đây là biểu mẫu sử dụng bộ tiền xử lý #define để xác định một hằng số -

#define identifier value

Ví dụ sau giải thích nó một cách chi tiết -

#import <Foundation/Foundation.h>

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

int main() {
   int area;
   area = LENGTH * WIDTH;
   NSLog(@"value of area : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-07 22:18:16.637 demo[21460] value of area : 50
2013-09-07 22:18:16.638 demo[21460]

Từ khoá const

Bạn có thể dùng const tiền tố để khai báo các hằng với một kiểu cụ thể như sau:

const type variable = value;

Ví dụ sau giải thích nó một cách chi tiết -

#import <Foundation/Foundation.h>

int main() {
   const int  LENGTH = 10;
   const int  WIDTH  = 5;
   const char NEWLINE = '\n';
   int area;  
   
   area = LENGTH * WIDTH;
   NSLog(@"value of area : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-07 22:19:24.780 demo[25621] value of area : 50
2013-09-07 22:19:24.781 demo[25621]

Lưu ý rằng đó là một thực hành lập trình tốt để xác định hằng số trong CHỮ HOA.

Một toán tử là một ký hiệu yêu cầu trình biên dịch thực hiện các thao tác toán học hoặc logic cụ thể. Ngôn ngữ Objective-C có nhiều toán tử tích hợp sẵn và cung cấp các loại toán tử sau:

  • Toán tử số học
  • Toán tử quan hệ
  • Toán tử logic
  • Toán tử Bitwise
  • Người điều hành nhiệm vụ
  • Nhà điều hành khác

Hướng dẫn này sẽ giải thích từng toán tử số học, quan hệ, logic, bitwise, phép gán và các toán tử khác.

Toán tử số học

Bảng sau hiển thị tất cả các toán tử số học được hỗ trợ bởi ngôn ngữ Objective-C. Giả sử biếnA giữ 10 và biến B giữ 20, sau đó -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
+ Thêm hai toán hạng A + B sẽ cho 30
- Trừ toán hạng thứ hai với toán hạng đầu tiên A - B sẽ cho -10
* Nhân cả hai toán hạng A * B sẽ cho 200
/ Chia tử số cho mẫu số B / A sẽ cho 2
% Toán tử mô đun và phần còn lại của sau một phép chia số nguyên B% A sẽ cho 0
++ Toán tử tăng dần làm tăng giá trị số nguyên lên một A ++ sẽ cho 11
- Toán tử giảm dần giảm giá trị số nguyên đi một A-- sẽ cho 9

Toán tử quan hệ

Bảng sau hiển thị tất cả các toán tử quan hệ được hỗ trợ bởi ngôn ngữ Objective-C. Giả sử biếnA giữ 10 và biến B giữ 20, sau đó -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
== Kiểm tra xem giá trị của hai toán hạng có bằng nhau hay không; nếu có, thì điều kiện trở thành đúng. (A == B) không đúng.
! = Kiểm tra xem giá trị của hai toán hạng có bằng nhau hay không; nếu các giá trị không bằng nhau, thì điều kiện trở thành true. (A! = B) là đúng.
> Kiểm tra xem giá trị của toán hạng bên trái có lớn hơn giá trị của toán hạng bên phải hay không; nếu có, thì điều kiện trở thành đúng. (A> B) là không đúng.
< Kiểm tra nếu giá trị của toán hạng bên trái nhỏ hơn giá trị của toán hạng bên phải; nếu có, thì điều kiện trở thành đúng. (A <B) là đúng.
> = Kiểm tra nếu giá trị của toán hạng bên trái lớn hơn hoặc bằng giá trị của toán hạng bên phải; nếu có, thì điều kiện trở thành đúng. (A> = B) là không đúng.
<= Kiểm tra nếu giá trị của toán hạng bên trái nhỏ hơn hoặc bằng giá trị của toán hạng bên phải; nếu có, thì điều kiện trở thành đúng. (A <= B) là đúng.

Toán tử logic

Bảng sau đây hiển thị tất cả các toán tử logic được hỗ trợ bởi ngôn ngữ Objective-C. Giả sử biếnA giữ 1 và biến B giữ 0, sau đó -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
&& Được gọi là toán tử logic AND. Nếu cả hai toán hạng đều khác 0 thì điều kiện trở thành true. (A && B) là sai.
|| Được gọi là Toán tử logic HOẶC. Nếu bất kỳ toán hạng nào trong hai toán hạng khác 0 thì điều kiện trở thành true. (A || B) là đúng.
! Được gọi là Toán tử logic NOT. Sử dụng để đảo ngược trạng thái logic của toán hạng của nó. Nếu một điều kiện là đúng, thì toán tử logic NOT sẽ sai. ! (A && B) là đúng.

Toán tử Bitwise

Toán tử bitwise hoạt động trên các bit và thực hiện thao tác từng bit. Bảng sự thật cho &, |, và ^ như sau:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Giả sử nếu A = 60; và B = 13; bây giờ ở định dạng nhị phân, chúng sẽ như sau:

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

Các toán tử Bitwise được hỗ trợ bởi ngôn ngữ Objective-C được liệt kê trong bảng sau. Giả sử biến A giữ 60 và biến B giữ 13 thì -

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
& Toán tử AND nhị phân sao chép một bit vào kết quả nếu nó tồn tại trong cả hai toán hạng. (A & B) sẽ cho 12, là 0000 1100
| Toán tử OR nhị phân sao chép một bit nếu nó tồn tại trong một trong hai toán hạng. (A | B) sẽ cho 61, là 0011 1101
^ Toán tử XOR nhị phân sao chép bit nếu nó được đặt trong một toán hạng nhưng không phải cả hai. (A ^ B) sẽ cho 49, là 0011 0001
~ Toán tử bổ sung số nhị phân là một ngôi và có tác dụng 'lật' các bit. (~ A) sẽ cho -61, là 1100 0011 ở dạng phần bù của 2.
<< Toán tử dịch chuyển trái nhị phân. Giá trị toán hạng bên trái được di chuyển sang trái bằng số bit được chỉ định bởi toán hạng bên phải. A << 2 sẽ cho 240, là 1111 0000
>> Toán tử Shift phải nhị phân. Giá trị của toán hạng bên trái được di chuyển sang phải bằng số bit được chỉ định bởi toán hạng bên phải. A >> 2 sẽ cho 15, là 0000 1111

Người điều hành nhiệm vụ

Có các toán tử gán sau được ngôn ngữ Objective-C hỗ trợ:

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
= Toán tử gán đơn giản, Gán giá trị từ toán hạng bên phải sang toán hạng bên trái C = A + B sẽ gán giá trị của A + B vào C
+ = Thêm toán tử gán AND, Nó thêm toán hạng bên phải vào toán hạng bên trái và gán kết quả cho toán hạng bên trái C + = A tương đương với C = C + A
- = Trừ toán tử gán AND, Nó trừ toán hạng phải khỏi toán hạng bên trái và gán kết quả cho toán hạng trái C - = A tương đương với C = C - A
* = Nhân toán tử gán AND, Nó nhân toán hạng phải với toán hạng trái và gán kết quả cho toán hạng trái C * = A tương đương với C = C * A
/ = Toán tử gán AND, Nó chia toán hạng bên trái với toán hạng bên phải và gán kết quả cho toán hạng bên trái C / = A tương đương với C = C / A
% = Toán tử gán mô-đun AND, cần mô-đun sử dụng hai toán hạng và gán kết quả cho toán hạng bên trái C% = A tương đương với C = C% A
<< = Dịch chuyển trái và toán tử gán C << = 2 giống với C = C << 2
>> = Toán tử chuyển nhượng AND phải C >> = 2 giống với C = C >> 2
& = Toán tử gán bitwise AND C & = 2 giống C = C & 2
^ = OR độc quyền bit và toán tử gán C ^ = 2 giống với C = C ^ 2
| = bao gồm bitwise OR và toán tử gán C | = 2 tương tự như C = C | 2

Các toán tử khác ↦ sizeof & ternary

Có một số toán tử quan trọng khác bao gồm sizeof? : được hỗ trợ bởi Objective-C Language.

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
sizeof () Trả về kích thước của một biến. sizeof (a), trong đó a là số nguyên, sẽ trả về 4.
& Trả về địa chỉ của một biến. & a; sẽ cung cấp địa chỉ thực của biến.
* Con trỏ đến một biến. * a; sẽ trỏ đến một biến.
? : Biểu thức điều kiện Nếu Điều kiện là đúng? Sau đó giá trị X: Ngược lại giá trị Y

Quyền ưu tiên của người vận hành trong Objective-C

Mức độ ưu tiên của toán tử xác định nhóm các từ trong một biểu thức. Điều này ảnh hưởng đến cách một biểu thức được đánh giá. Các toán tử nhất định có quyền ưu tiên cao hơn những toán tử khác; ví dụ, toán tử nhân có mức độ ưu tiên cao hơn toán tử cộng -

Ví dụ: x = 7 + 3 * 2; ở đây, x được gán 13, không phải 20 vì toán tử * có mức độ ưu tiên cao hơn +, vì vậy đầu tiên nó được nhân với 3 * 2 và sau đó cộng thành 7.

Ở đây, các toán tử có mức độ ưu tiên cao nhất xuất hiện ở đầu bảng, những toán tử có mức độ ưu tiên thấp nhất xuất hiện ở cuối bảng. Trong một biểu thức, các toán tử có mức độ ưu tiên cao hơn sẽ được đánh giá đầu tiên.

thể loại  Nhà điều hành  Sự liên kết 
Postfix  () [] ->. ++ - -   Trái sang phải 
Một ngôi  + -! ~ ++ - - (type) * & sizeof  Phải sang trái 
Phép nhân   * /%  Trái sang phải 
Phụ gia   + -  Trái sang phải 
Shift   << >>  Trái sang phải 
Quan hệ   <<=>> =  Trái sang phải 
Bình đẳng   ==! =  Trái sang phải 
Bitwise XOR  Trái sang phải 
Bitwise HOẶC  Trái sang phải 
Logic AND  &&  Trái sang phải 
Logic HOẶC  ||  Trái sang phải 
Có điều kiện  ?:  Phải sang trái 
Chuyển nhượng  = + = - = * = / =% = >> = << = & = ^ = | =  Phải sang trái 
Dấu phẩy  Trái sang phải 

Có thể có một tình huống, khi bạn cần thực thi một khối mã nhiều lần. Nói chung, các câu lệnh được thực hiện tuần tự: Câu lệnh đầu tiên trong một hàm được thực hiện đầu tiên, tiếp theo là câu lệnh thứ hai, v.v.

Các ngôn ngữ lập trình cung cấp các cấu trúc điều khiển khác nhau cho phép các đường dẫn thực thi phức tạp hơn.

Câu lệnh lặp cho phép chúng ta thực hiện một câu lệnh hoặc một nhóm câu lệnh nhiều lần và sau đây là dạng chung của câu lệnh lặp trong hầu hết các ngôn ngữ lập trình:

Ngôn ngữ lập trình Objective-C cung cấp các loại vòng lặp sau để xử lý các yêu cầu về lặp. Nhấp vào các liên kết sau để kiểm tra chi tiết của chúng.

Sr.No. Loại vòng lặp & Mô tả
1 trong khi lặp lại

Lặp lại một câu lệnh hoặc một nhóm câu lệnh trong khi một điều kiện đã cho là đúng. Nó kiểm tra điều kiện trước khi thực thi phần thân của vòng lặp.

2 vòng lặp for

Thực thi một chuỗi các câu lệnh nhiều lần và viết tắt mã quản lý biến vòng lặp.

3 vòng lặp do ... while

Giống như một câu lệnh while, ngoại trừ việc nó kiểm tra điều kiện ở cuối thân vòng lặp.

4 vòng lồng nhau

Bạn có thể sử dụng một hoặc nhiều vòng lặp bên trong bất kỳ vòng lặp while, for hoặc do.. while nào khác.

Tuyên bố kiểm soát vòng lặp

Các câu lệnh điều khiển vòng lặp thay đổi việc thực thi từ trình tự bình thường của nó. Khi việc thực thi rời khỏi một phạm vi, tất cả các đối tượng tự động được tạo trong phạm vi đó sẽ bị phá hủy.

Objective-C hỗ trợ các câu lệnh điều khiển sau. Nhấp vào các liên kết sau để kiểm tra chi tiết của chúng.

Sr.No. Tuyên bố & Mô tả Kiểm soát
1 tuyên bố ngắt

Chấm dứt loop hoặc là switch và chuyển việc thực thi đến câu lệnh ngay sau vòng lặp hoặc chuyển đổi.

2 tiếp tục tuyên bố

Làm cho vòng lặp bỏ qua phần còn lại của phần thân và ngay lập tức kiểm tra lại tình trạng của nó trước khi nhắc lại.

Vòng lặp vô hạn

Một vòng lặp trở thành vòng lặp vô hạn nếu một điều kiện không bao giờ trở thành sai. Cácforvòng lặp thường được sử dụng cho mục đích này. Vì không có biểu thức nào trong ba biểu thức tạo thành vòng lặp for được yêu cầu, bạn có thể tạo một vòng lặp vô tận bằng cách để trống biểu thức điều kiện.

#import <Foundation/Foundation.h>
 
int main () {

   for( ; ; ) {
      NSLog(@"This loop will run forever.\n");
   }

   return 0;
}

Khi biểu thức điều kiện vắng mặt, nó được giả định là đúng. Bạn có thể có một biểu thức khởi tạo và tăng dần, nhưng các lập trình viên Objective-C thường sử dụng cấu trúc for (;;) để biểu thị một vòng lặp vô hạn.

Cấu trúc ra quyết định yêu cầu người lập trình chỉ định một hoặc nhiều điều kiện để được đánh giá hoặc kiểm tra bởi chương trình, cùng với một câu lệnh hoặc các câu lệnh sẽ được thực thi nếu điều kiện đó được xác định là đúng và tùy chọn, các câu lệnh khác được thực thi nếu điều kiện được xác định là sai.

Sau đây là dạng chung của cấu trúc ra quyết định điển hình được tìm thấy trong hầu hết các ngôn ngữ lập trình:

Ngôn ngữ lập trình Objective-C giả định bất kỳ non-zeronon-null giá trị như true, và nếu nó là zero hoặc là null, sau đó nó được giả định là false giá trị.

Ngôn ngữ lập trình Objective-C cung cấp các loại câu lệnh ra quyết định sau. Nhấp vào các liên kết sau để kiểm tra chi tiết của chúng -

Sr.No. Tuyên bố & Mô tả
1 câu lệnh if

An if statement bao gồm một biểu thức boolean theo sau bởi một hoặc nhiều câu lệnh.

2 câu lệnh if ... else

An if statement có thể được theo sau bởi một tùy chọn else statement, thực thi khi biểu thức boolean sai.

3 câu lệnh if lồng nhau

Bạn có thể sử dụng một if hoặc là else if tuyên bố bên trong khác if hoặc là else if các câu lệnh).

4 chuyển đổi tuyên bố

A switch câu lệnh cho phép một biến được kiểm tra tính bình đẳng với một danh sách các giá trị.

5 các câu lệnh chuyển đổi lồng nhau

Bạn có thể sử dụng một switch tuyên bố bên trong khác switch các câu lệnh).

Các ? : Nhà điều hành

Chúng tôi đã bảo hiểm conditional operator ? : trong chương trước có thể được sử dụng để thay thế if...elsecác câu lệnh. Nó có dạng chung sau:

Exp1 ? Exp2 : Exp3;

Trong đó Exp1, Exp2 và Exp3 là các biểu thức. Chú ý công dụng và vị trí của dấu hai chấm.

Giá trị của a? biểu thức được xác định như thế này: Exp1 được đánh giá. Nếu nó là true, thì Exp2 được đánh giá và trở thành giá trị của toàn bộ? biểu hiện. Nếu Exp1 là false, thì Exp3 được đánh giá và giá trị của nó trở thành giá trị của biểu thức.

Hàm là một nhóm các câu lệnh cùng thực hiện một tác vụ. Mỗi chương trình Objective-C đều có một hàm C, đó làmain(), và tất cả các chương trình tầm thường nhất có thể xác định các chức năng bổ sung.

Bạn có thể chia mã của mình thành các chức năng riêng biệt. Cách bạn phân chia mã của mình giữa các chức năng khác nhau là tùy thuộc vào bạn, nhưng về mặt logic, việc phân chia thường là để mỗi chức năng thực hiện một nhiệm vụ cụ thể.

Một chức năng declarationcho trình biên dịch biết về tên, kiểu trả về và các tham số của hàm. Một chức năngdefinition cung cấp phần thân thực tế của hàm.

Về cơ bản trong Objective-C, chúng ta gọi hàm là phương thức.

Khung nền tảng Objective-C cung cấp nhiều phương thức tích hợp sẵn mà chương trình của bạn có thể gọi. Ví dụ, phương phápappendString() để nối chuỗi vào một chuỗi khác.

Một phương thức được biết đến với nhiều tên khác nhau như một hàm hoặc một quy trình con hoặc một thủ tục, v.v.

Xác định một phương pháp

Dạng tổng quát của định nghĩa phương thức trong ngôn ngữ lập trình Objective-C như sau:

- (return_type) method_name:( argumentType1 )argumentName1 
joiningArgument2:( argumentType2 )argumentName2 ... 
joiningArgumentn:( argumentTypen )argumentNamen {
   body of the function
}

Định nghĩa phương thức trong ngôn ngữ lập trình Objective-C bao gồm tiêu đề phương thứcthân phương thức . Đây là tất cả các phần của một phương pháp -

  • Return Type- Một phương thức có thể trả về một giá trị. Cácreturn_typelà kiểu dữ liệu của giá trị mà hàm trả về. Một số phương thức thực hiện các hoạt động mong muốn mà không trả về giá trị. Trong trường hợp này, return_type là từ khóavoid.

  • Method Name- Đây là tên thực của phương thức. Tên phương thức và danh sách tham số cùng nhau tạo thành chữ ký phương thức.

  • Arguments- Một đối số giống như một trình giữ chỗ. Khi một hàm được gọi, bạn truyền một giá trị cho đối số. Giá trị này được gọi là tham số hoặc đối số thực tế. Danh sách tham số đề cập đến kiểu, thứ tự và số lượng các đối số của một phương thức. Đối số là tùy chọn; nghĩa là, một phương thức có thể không chứa đối số.

  • Joining Argument - Đối số nối là để làm cho nó dễ đọc hơn và làm cho nó rõ ràng trong khi gọi nó.

  • Method Body - Phần thân của phương thức chứa một tập hợp các câu lệnh xác định chức năng của phương thức.

Thí dụ

Sau đây là mã nguồn cho một phương thức được gọi là max(). Phương thức này nhận hai tham số num1 và num2 và trả về giá trị tối đa giữa hai tham số:

/* function returning the max between two numbers */
- (int) max:(int) num1 secondNumber:(int) num2 {
   
   /* local variable declaration */
   int result;
 
   if (num1 > num2) {
      result = num1;
   } else {
      result = num2;
   }
 
   return result; 
}

Khai báo phương pháp

Một phương pháp declarationcho trình biên dịch biết về tên hàm và cách gọi phương thức. Phần thân thực của hàm có thể được định nghĩa riêng biệt.

Một khai báo phương thức có các phần sau:

- (return_type) function_name:( argumentType1 )argumentName1 
joiningArgument2:( argumentType2 )argumentName2 ... 
joiningArgumentn:( argumentTypen )argumentNamen;

Đối với hàm max () được định nghĩa ở trên, sau đây là khai báo phương thức:

-(int) max:(int)num1 andNum2:(int)num2;

Khai báo phương thức là bắt buộc khi bạn xác định một phương thức trong một tệp nguồn và bạn gọi phương thức đó trong một tệp khác. Trong trường hợp này, bạn nên khai báo hàm ở đầu tệp gọi hàm.

Gọi một phương thức

Trong khi tạo phương thức Objective-C, bạn đưa ra định nghĩa về những gì hàm phải làm. Để sử dụng một phương thức, bạn sẽ phải gọi hàm đó để thực hiện tác vụ đã xác định.

Khi một chương trình gọi một hàm, điều khiển chương trình được chuyển sang phương thức được gọi. Một phương thức được gọi thực hiện tác vụ đã xác định và khi câu lệnh trả về của nó được thực thi hoặc khi đạt đến dấu ngoặc nhọn kết thúc hàm, nó sẽ trả lại điều khiển chương trình trở lại chương trình chính.

Để gọi một phương thức, bạn chỉ cần chuyển các tham số bắt buộc cùng với tên phương thức và nếu phương thức trả về một giá trị, thì bạn có thể lưu trữ giá trị trả về. Ví dụ -

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
/* method declaration */
- (int)max:(int)num1 andNum2:(int)num2;
@end

@implementation SampleClass

/* method returning the max between two numbers */
- (int)max:(int)num1 andNum2:(int)num2 {

   /* local variable declaration */
   int result;
 
   if (num1 > num2) {
      result = num1;
   } else {
      result = num2;
   }
 
   return result; 
}

@end

int main () {
   
   /* local variable definition */
   int a = 100;
   int b = 200;
   int ret;
   
   SampleClass *sampleClass = [[SampleClass alloc]init];

   /* calling a method to get max value */
   ret = [sampleClass max:a andNum2:b];
 
   NSLog(@"Max value is : %d\n", ret );
   return 0;
}

Tôi đã giữ hàm max () cùng với hàm main () và tuân thủ mã nguồn. Trong khi chạy tệp thực thi cuối cùng, nó sẽ tạo ra kết quả sau:

2013-09-07 22:28:45.912 demo[26080] Max value is : 200

Đối số hàm

Nếu một hàm sử dụng các đối số, nó phải khai báo các biến chấp nhận giá trị của các đối số. Các biến này được gọi làformal parameters của hàm.

Các tham số chính thức hoạt động giống như các biến cục bộ khác bên trong hàm và được tạo khi nhập vào hàm và bị hủy khi thoát.

Trong khi gọi một hàm, có hai cách mà các đối số có thể được truyền cho một hàm:

Sr.No. Loại & Mô tả Cuộc gọi
1 Gọi theo giá trị

Phương thức này sao chép giá trị thực của một đối số vào tham số chính thức của hàm. Trong trường hợp này, các thay đổi được thực hiện đối với tham số bên trong hàm không ảnh hưởng đến đối số.

2 Gọi bằng cách tham khảo

Phương thức này sao chép địa chỉ của một đối số vào tham số chính thức. Bên trong hàm, địa chỉ được sử dụng để truy cập đối số thực được sử dụng trong lệnh gọi. Điều này có nghĩa là các thay đổi được thực hiện đối với tham số sẽ ảnh hưởng đến đối số.

Theo mặc định, Objective-C sử dụng call by valueđể chuyển đối số. Nói chung, điều này có nghĩa là mã trong một hàm không thể thay đổi các đối số được sử dụng để gọi hàm và ví dụ nêu trên khi gọi hàm max () được sử dụng cùng một phương thức.

Một lớp Objective-C định nghĩa một đối tượng kết hợp dữ liệu với hành vi liên quan. Đôi khi, nó có ý nghĩa khi chỉ đại diện cho một nhiệm vụ hoặc đơn vị hành vi, thay vì một tập hợp các phương pháp.

Các khối là một tính năng cấp ngôn ngữ được thêm vào C, Objective-C và C ++, cho phép bạn tạo các đoạn mã riêng biệt có thể được chuyển cho các phương thức hoặc hàm như thể chúng là các giá trị. Các khối là các đối tượng Objective-C có nghĩa là chúng có thể được thêm vào các bộ sưu tập như NSArray hoặc NSDictionary. Chúng cũng có khả năng nắm bắt các giá trị từ phạm vi bao quanh, làm cho chúng tương tự như các bao đóng hoặc lambdas trong các ngôn ngữ lập trình khác

Cú pháp khai báo khối đơn giản

returntype (^blockName)(argumentType);

Triển khai khối đơn giản

returntype (^blockName)(argumentType)= ^{
};

Đây là một ví dụ đơn giản

void (^simpleBlock)(void) = ^{
   NSLog(@"This is a block");
};

Chúng ta có thể gọi khối bằng cách sử dụng

simpleBlock();

Khối Lập luận và Trả lại Giá trị

Các khối cũng có thể nhận đối số và trả về giá trị giống như các phương thức và hàm.

Đây là một ví dụ đơn giản để triển khai và gọi một khối với các đối số và giá trị trả về.

double (^multiplyTwoValues)(double, double) = 
   ^(double firstValue, double secondValue) {
      return firstValue * secondValue;
   };

double result = multiplyTwoValues(2,4); 
NSLog(@"The result is %f", result);

Các khối sử dụng định nghĩa loại

Đây là một ví dụ đơn giản sử dụng typedef trong khối. Hãy lưu ý mẫu nàydoesn't work trên online compilerbây giờ. Sử dụngXCode để chạy giống nhau.

#import <Foundation/Foundation.h>

typedef void (^CompletionBlock)();
@interface SampleClass:NSObject
- (void)performActionWithCompletion:(CompletionBlock)completionBlock;
@end

@implementation SampleClass

- (void)performActionWithCompletion:(CompletionBlock)completionBlock {

   NSLog(@"Action Performed");
   completionBlock();
}

@end

int main() {
   
   /* my first program in Objective-C */
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass performActionWithCompletion:^{
      NSLog(@"Completion is called to intimate action is performed.");
   }];

   return 0;
}

Hãy để chúng tôi biên dịch và thực thi nó, nó sẽ tạo ra kết quả sau:

2013-09-10 08:13:57.155 demo[284:303] Action Performed
2013-09-10 08:13:57.157 demo[284:303] Completion is called to intimate action is performed.

Các khối được sử dụng nhiều hơn trong các ứng dụng iOS và Mac OS X. Vì vậy, việc hiểu cách sử dụng các khối càng quan trọng hơn.

Trong ngôn ngữ lập trình Objective-C, để lưu các kiểu dữ liệu cơ bản như int, float, bool ở dạng đối tượng,

Objective-C cung cấp một loạt các phương pháp để làm việc với NSNumber và những phương pháp quan trọng được liệt kê trong bảng sau.

Sr.No. Phương pháp & Mô tả
1

+ (NSNumber *)numberWithBool:(BOOL)value

Tạo và trả về một đối tượng NSNumber chứa một giá trị nhất định, coi nó như một BOOL.

2

+ (NSNumber *)numberWithChar:(char)value

Tạo và trả về một đối tượng NSNumber chứa một giá trị đã cho, coi nó như một ký tự có dấu.

3

+ (NSNumber *)numberWithDouble:(double)value

Tạo và trả về một đối tượng NSNumber chứa một giá trị nhất định, coi nó như một giá trị kép.

4

+ (NSNumber *)numberWithFloat:(float)value

Tạo và trả về một đối tượng NSNumber có chứa một giá trị nhất định, coi nó như một số thực.

5

+ (NSNumber *)numberWithInt:(int)value

Tạo và trả về một đối tượng NSNumber chứa một giá trị nhất định, coi nó như một số nguyên có dấu.

6

+ (NSNumber *)numberWithInteger:(NSInteger)value

Tạo và trả về một đối tượng NSNumber chứa một giá trị nhất định, coi nó như một NSInteger.

7

- (BOOL)boolValue

Trả về giá trị của người nhận dưới dạng BOOL.

số 8

- (char)charValue

Trả về giá trị của người nhận dưới dạng một ký tự.

9

- (double)doubleValue

Trả về giá trị của người nhận dưới dạng một giá trị kép.

10

- (float)floatValue

Trả về giá trị của người nhận dưới dạng một số thực.

11

- (NSInteger)integerValue

Trả về giá trị của người nhận dưới dạng NSInteger.

12

- (int)intValue

Trả về giá trị của người nhận dưới dạng int.

13

- (NSString *)stringValue

Trả về giá trị của người nhận dưới dạng một chuỗi mà con người có thể đọc được.

Đây là một ví dụ đơn giản để sử dụng NSNumber nhân hai số và trả về sản phẩm.

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b;
@end

@implementation SampleClass

- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
   float number1 = [a floatValue];
   float number2 = [b floatValue];
   float product = number1 * number2;
   NSNumber *result = [NSNumber numberWithFloat:product];
   return result;
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

   SampleClass *sampleClass = [[SampleClass alloc]init];
   NSNumber *a = [NSNumber numberWithFloat:10.5];
   NSNumber *b = [NSNumber numberWithFloat:10.0];   
   NSNumber *result = [sampleClass multiplyA:a withB:b];
   NSString *resultString = [result stringValue];
   NSLog(@"The product is %@",resultString);

   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-14 18:53:40.575 demo[16787] The product is 105

Ngôn ngữ lập trình Objective-C cung cấp một cấu trúc dữ liệu được gọi là the array, có thể lưu trữ tập hợp tuần tự có kích thước cố định của các phần tử cùng loại. Mảng được sử dụng để lưu trữ một tập hợp dữ liệu, nhưng thường hữu ích hơn nếu coi một mảng là một tập hợp các biến cùng kiểu.

Thay vì khai báo các biến riêng lẻ, chẳng hạn như number0, number1, ... và number99, bạn khai báo một biến mảng chẳng hạn như số và sử dụng số [0], số [1] và ..., số [99] để biểu diễn các biến riêng lẻ. Một phần tử cụ thể trong một mảng được truy cập bởi một chỉ mục.

Tất cả các mảng bao gồm các vị trí bộ nhớ liền nhau. Địa chỉ thấp nhất tương ứng với phần tử đầu tiên và địa chỉ cao nhất cho phần tử cuối cùng.

Khai báo Mảng

Để khai báo một mảng trong Objective-C, một lập trình viên chỉ định kiểu của các phần tử và số phần tử theo yêu cầu của một mảng như sau:

type arrayName [ arraySize ];

Đây được gọi là mảng một chiều . CácarraySize phải là một hằng số nguyên lớn hơn 0 và typecó thể là bất kỳ kiểu dữ liệu Objective-C hợp lệ nào. Ví dụ, để khai báo một mảng 10 phần tử được gọi làbalance kiểu double, hãy sử dụng câu lệnh này -

double balance[10];

Bây giờ, số dư là một mảng biến đổi, đủ để chứa tối đa 10 số kép.

Khởi tạo Mảng

Bạn có thể khởi tạo một mảng trong Objective-C hoặc từng cái một hoặc sử dụng một câu lệnh như sau:

double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Số lượng giá trị giữa các dấu ngoặc vuông {} không được lớn hơn số phần tử mà chúng ta khai báo cho mảng giữa các dấu ngoặc vuông []. Sau đây là một ví dụ để gán một phần tử duy nhất của mảng:

Nếu bạn bỏ qua kích thước của mảng, một mảng vừa đủ lớn để chứa quá trình khởi tạo sẽ được tạo. Do đó, nếu bạn viết -

double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};

Bạn sẽ tạo chính xác mảng giống như bạn đã làm trong ví dụ trước.

balance[4] = 50.0;

Câu lệnh trên gán giá trị phần tử thứ 5 trong mảng là 50.0. Mảng có chỉ số thứ 4 sẽ là thứ 5, tức là phần tử cuối cùng vì tất cả các mảng đều có 0 là chỉ số của phần tử đầu tiên của chúng mà còn được gọi là chỉ số cơ sở. Sau đây là biểu diễn bằng hình ảnh của cùng một mảng mà chúng ta đã thảo luận ở trên -

Truy cập các phần tử mảng

Một phần tử được truy cập bằng cách đánh chỉ mục tên mảng. Điều này được thực hiện bằng cách đặt chỉ mục của phần tử trong dấu ngoặc vuông sau tên của mảng. Ví dụ -

double salary = balance[9];

Câu lệnh trên sẽ lấy phần tử thứ 10 từ mảng và gán giá trị cho biến lương. Sau đây là một ví dụ, sẽ sử dụng tất cả ba khái niệm đã đề cập ở trên viz. khai báo, gán và truy cập mảng -

#import <Foundation/Foundation.h>
 
int main () {
   int n[ 10 ];   /* n is an array of 10 integers */
   int i,j;
 
   /* initialize elements of array n to 0 */         
   for ( i = 0; i < 10; i++ ) {
      n[ i ] = i + 100;    /* set element at location i to i + 100 */
   }
   
   /* output each array element's value */
   for (j = 0; j < 10; j++ ) {
      NSLog(@"Element[%d] = %d\n", j, n[j] );
   }
 
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 01:24:06.669 demo[16508] Element[0] = 100
2013-09-14 01:24:06.669 demo[16508] Element[1] = 101
2013-09-14 01:24:06.669 demo[16508] Element[2] = 102
2013-09-14 01:24:06.669 demo[16508] Element[3] = 103
2013-09-14 01:24:06.669 demo[16508] Element[4] = 104
2013-09-14 01:24:06.669 demo[16508] Element[5] = 105
2013-09-14 01:24:06.669 demo[16508] Element[6] = 106
2013-09-14 01:24:06.669 demo[16508] Element[7] = 107
2013-09-14 01:24:06.669 demo[16508] Element[8] = 108
2013-09-14 01:24:06.669 demo[16508] Element[9] = 109

Chi tiết Mảng Objective-C

Mảng rất quan trọng đối với Objective-C và cần nhiều chi tiết hơn. Có một vài khái niệm quan trọng sau đây liên quan đến mảng mà lập trình viên Objective-C phải rõ ràng:

Sr.No. Khái niệm & Mô tả
1 Mảng đa chiều

Objective-C hỗ trợ mảng nhiều chiều. Dạng đơn giản nhất của mảng nhiều chiều là mảng hai chiều.

2 Truyền mảng cho các hàm

Bạn có thể chuyển cho hàm một con trỏ tới một mảng bằng cách chỉ định tên của mảng mà không có chỉ mục.

3 Trả về mảng từ một hàm

Objective-C cho phép một hàm trả về một mảng.

4 Con trỏ đến một mảng

Bạn có thể tạo một con trỏ đến phần tử đầu tiên của mảng bằng cách chỉ định tên mảng mà không cần bất kỳ chỉ mục nào.

Các con trỏ trong Objective-C rất dễ học và thú vị. Một số tác vụ lập trình Objective-C được thực hiện dễ dàng hơn với con trỏ và các tác vụ khác, chẳng hạn như cấp phát bộ nhớ động, không thể thực hiện nếu không sử dụng con trỏ. Vì vậy, việc học các con trỏ để trở thành một lập trình viên Objective-C hoàn hảo trở nên cần thiết. Hãy bắt đầu học chúng theo các bước đơn giản và dễ dàng.

Như bạn đã biết, mọi biến là một vị trí bộ nhớ và mọi vị trí bộ nhớ đều có địa chỉ của nó được xác định có thể được truy cập bằng cách sử dụng toán tử dấu và (&), biểu thị một địa chỉ trong bộ nhớ. Hãy xem xét ví dụ sau, ví dụ này sẽ in ra địa chỉ của các biến được xác định:

#import <Foundation/Foundation.h>

int main () {
   int  var1;
   char var2[10];

   NSLog(@"Address of var1 variable: %x\n", &var1 );
   NSLog(@"Address of var2 variable: %x\n", &var2 );

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

2013-09-13 03:18:45.727 demo[17552] Address of var1 variable: 1c0843fc
2013-09-13 03:18:45.728 demo[17552] Address of var2 variable: 1c0843f0

Như vậy, bạn đã hiểu địa chỉ bộ nhớ là gì và cách truy cập nó, vậy là cơ sở của khái niệm đã kết thúc. Bây giờ chúng ta hãy xem con trỏ là gì.

Con trỏ là gì?

A pointerlà một biến có giá trị là địa chỉ của một biến khác, tức là địa chỉ trực tiếp của vị trí bộ nhớ. Giống như bất kỳ biến hoặc hằng số nào, bạn phải khai báo một con trỏ trước khi có thể sử dụng nó để lưu trữ bất kỳ địa chỉ biến nào. Dạng chung của khai báo biến con trỏ là:

type *var-name;

Đây, typelà kiểu cơ sở của con trỏ; nó phải là kiểu dữ liệu Objective-C hợp lệ vàvar-namelà tên của biến con trỏ. Dấu hoa thị * mà bạn sử dụng để khai báo một con trỏ giống với dấu hoa thị mà bạn sử dụng cho phép nhân. Tuy nhiên, trong câu lệnh này, dấu hoa thị được sử dụng để chỉ định một biến làm con trỏ. Sau đây là khai báo con trỏ hợp lệ:

int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

Kiểu dữ liệu thực tế của giá trị của tất cả các con trỏ, cho dù là số nguyên, số thực, ký tự hay cách khác, đều giống nhau, một số thập lục phân dài đại diện cho địa chỉ bộ nhớ. Sự khác biệt duy nhất giữa các con trỏ của các kiểu dữ liệu khác nhau là kiểu dữ liệu của biến hoặc hằng số mà con trỏ trỏ tới.

Làm thế nào để sử dụng Con trỏ?

Có một số thao tác quan trọng mà chúng tôi sẽ thực hiện với sự trợ giúp của con trỏ rất thường xuyên. (a) chúng tôi xác định một biến con trỏ, (b) gán địa chỉ của một biến cho một con trỏ, và (c)cuối cùng là truy cập giá trị tại địa chỉ có sẵn trong biến con trỏ. Điều này được thực hiện bằng cách sử dụng toán tử một ngôi*trả về giá trị của biến nằm tại địa chỉ được chỉ định bởi toán hạng của nó. Ví dụ sau sử dụng các thao tác này:

#import <Foundation/Foundation.h>

int main () {
   int  var = 20;    /* actual variable declaration */
   int  *ip;         /* pointer variable declaration */  
   ip = &var;       /* store address of var in pointer variable*/

   NSLog(@"Address of var variable: %x\n", &var  );

   /* address stored in pointer variable */
   NSLog(@"Address stored in ip variable: %x\n", ip );

   /* access the value using the pointer */
   NSLog(@"Value of *ip variable: %d\n", *ip );

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

2013-09-13 03:20:21.873 demo[24179] Address of var variable: 337ed41c
2013-09-13 03:20:21.873 demo[24179] Address stored in ip variable: 337ed41c
2013-09-13 03:20:21.874 demo[24179] Value of *ip variable: 20

Con trỏ NULL trong Objective-C

Việc gán giá trị NULL cho một biến con trỏ luôn là một phương pháp hay trong trường hợp bạn không có địa chỉ chính xác để gán. Điều này được thực hiện tại thời điểm khai báo biến. Một con trỏ được gán NULL được gọi lànull con trỏ.

Con trỏ NULL là một hằng số có giá trị bằng 0 được xác định trong một số thư viện chuẩn. Hãy xem xét chương trình sau:

#import <Foundation/Foundation.h>

int main () {
   int  *ptr = NULL;
   NSLog(@"The value of ptr is : %x\n", ptr  );
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-13 03:21:19.447 demo[28027] The value of ptr is : 0

Trên hầu hết các hệ điều hành, các chương trình không được phép truy cập bộ nhớ ở địa chỉ 0 vì bộ nhớ đó được hệ điều hành dành riêng. Tuy nhiên, địa chỉ bộ nhớ 0 có ý nghĩa đặc biệt; nó báo hiệu rằng con trỏ không nhằm mục đích trỏ đến vị trí bộ nhớ có thể truy cập được. Nhưng theo quy ước, nếu một con trỏ chứa giá trị null (không), nó được coi là không trỏ đến.

Để kiểm tra con trỏ null, bạn có thể sử dụng câu lệnh if như sau:

if(ptr)     /* succeeds if p is not null */
if(!ptr)    /* succeeds if p is null */

Chi tiết con trỏ Objective-C

Con trỏ có nhiều khái niệm nhưng dễ và chúng rất quan trọng đối với lập trình Objective-C. Có một vài khái niệm con trỏ quan trọng sau đây, mà lập trình viên Objective-C phải rõ ràng -

Sr.No. Khái niệm & Mô tả
1 Objective-C - Số học con trỏ

Có bốn toán tử số học có thể được sử dụng trên con trỏ: ++, -, +, -

2 Objective-C - Mảng con trỏ

Bạn có thể xác định mảng để chứa một số con trỏ.

3 Objective-C - Con trỏ tới con trỏ

Objective-C cho phép bạn có con trỏ trên một con trỏ, v.v.

4 Chuyển con trỏ đến các hàm trong Objective-C

Truyền một đối số theo tham chiếu hoặc theo địa chỉ đều cho phép đối số đã truyền được thay đổi trong hàm gọi bởi hàm được gọi.

5 Con trỏ trả về từ các hàm trong Objective-C

Objective-C cho phép một hàm trả về một con trỏ tới biến cục bộ, biến tĩnh và cả bộ nhớ được cấp phát động.

Chuỗi trong ngôn ngữ lập trình Objective-C được biểu diễn bằng NSString và lớp con của nó NSMutableString cung cấp một số cách để tạo các đối tượng chuỗi. Cách đơn giản nhất để tạo một đối tượng chuỗi là sử dụng cấu trúc Objective-C @ "..." -

NSString *greeting = @"Hello";

Dưới đây là một ví dụ đơn giản để tạo và in một chuỗi.

#import <Foundation/Foundation.h>

int main () {
   NSString *greeting = @"Hello";
   NSLog(@"Greeting message: %@\n", greeting );

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

2013-09-11 01:21:39.922 demo[23926] Greeting message: Hello

Objective-C hỗ trợ một loạt các phương pháp để thao tác các chuỗi -

Sr.No. Phương pháp & Mục đích
1

- (NSString *)capitalizedString;

Trả về biểu diễn viết hoa của người nhận.

2

- (unichar)characterAtIndex:(NSUInteger)index;

Trả về ký tự tại một vị trí mảng đã cho.

3

- (double)doubleValue;

Trả về giá trị dấu phẩy động của văn bản của người nhận dưới dạng giá trị kép.

4

- (float)floatValue;

Trả về giá trị dấu phẩy động của văn bản của người nhận dưới dạng số thực.

5

- (BOOL)hasPrefix:(NSString *)aString;

Trả về giá trị Boolean cho biết liệu một chuỗi đã cho có khớp với các ký tự đầu của bộ thu hay không.

6

- (BOOL)hasSuffix:(NSString *)aString;

Trả về giá trị Boolean cho biết liệu một chuỗi đã cho có khớp với các ký tự kết thúc của bộ thu hay không.

7

- (id)initWithFormat:(NSString *)format ...;

Trả về một đối tượng NSString được khởi tạo bằng cách sử dụng một chuỗi định dạng đã cho làm mẫu mà các giá trị đối số còn lại được thay thế.

số 8

- (NSInteger)integerValue;

Trả về giá trị NSInteger của văn bản của người nhận.

9

- (BOOL)isEqualToString:(NSString *)aString;

Trả về giá trị Boolean cho biết liệu một chuỗi đã cho có bằng với người nhận hay không bằng cách sử dụng so sánh dựa trên Unicode theo nghĩa đen.

10

- (NSUInteger)length;

Trả về số ký tự Unicode trong bộ thu.

11

- (NSString *)lowercaseString;

Trả về biểu diễn chữ thường của bộ thu.

12

- (NSRange)rangeOfString:(NSString *)aString;

Tìm và trả về phạm vi lần xuất hiện đầu tiên của một chuỗi đã cho trong bộ thu.

13

- (NSString *)stringByAppendingFormat:(NSString *)format ...;

Trả về một chuỗi được tạo bằng cách thêm vào bộ nhận một chuỗi được xây dựng từ một chuỗi định dạng đã cho và các đối số sau đây.

14

- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set;

Trả về một chuỗi mới được tạo bằng cách xóa từ cả hai đầu của các ký tự nhận có trong một tập ký tự nhất định.

15

- (NSString *)substringFromIndex:(NSUInteger)anIndex;

Trả về một chuỗi mới chứa các ký tự của người nhận từ chuỗi ở một chỉ mục nhất định đến cuối.

Ví dụ sau sử dụng một vài hàm được đề cập ở trên:

#import <Foundation/Foundation.h>

int main () {
   NSString *str1 = @"Hello";
   NSString *str2 = @"World";
   NSString *str3;
   int  len ;

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

   /* uppercase string */
   str3 = [str2 uppercaseString];
   NSLog(@"Uppercase String :  %@\n", str3 );

   /* concatenates str1 and str2 */
   str3 = [str1 stringByAppendingFormat:@"World"];
   NSLog(@"Concatenated string:   %@\n", str3 );

   /* total length of str3 after concatenation */
   len = [str3 length];
   NSLog(@"Length of Str3 :  %d\n", len );

   /* InitWithFormat */
   str3 = [[NSString alloc] initWithFormat:@"%@ %@",str1,str2];	
   NSLog(@"Using initWithFormat:   %@\n", str3 );
   [pool drain];

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả như sau:

2013-09-11 01:15:45.069 demo[30378] Uppercase String :  WORLD
2013-09-11 01:15:45.070 demo[30378] Concatenated string:   HelloWorld
2013-09-11 01:15:45.070 demo[30378] Length of Str3 :  10
2013-09-11 01:15:45.070 demo[30378] Using initWithFormat:   Hello World

Bạn có thể tìm thấy danh sách đầy đủ các phương thức liên quan đến Objective-C NSString trong NSString Class Reference.

Mảng Objective-C cho phép bạn xác định loại biến có thể chứa một số mục dữ liệu cùng loại nhưng structure là một kiểu dữ liệu khác do người dùng định nghĩa có sẵn trong lập trình Objective-C, cho phép bạn kết hợp các mục dữ liệu thuộc các loại khác nhau.

Cấu trúc được sử dụng để đại diện cho một bản ghi, Giả sử bạn muốn theo dõi các cuốn sách của mình trong thư viện. Bạn có thể muốn theo dõi các thuộc tính sau về mỗi cuốn sách -

  • Title
  • Author
  • Subject
  • Mã sách

Xác định cấu trúc

Để xác định cấu trúc, bạn phải sử dụng structtuyên bố. Câu lệnh struct xác định một kiểu dữ liệu mới, với nhiều hơn một thành viên cho chương trình của bạn. Định dạng của câu lệnh struct là:

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

Các structure taglà tùy chọn và mỗi định nghĩa thành viên là một định nghĩa biến bình thường, chẳng hạn như int i; hoặc float f; hoặc bất kỳ định nghĩa biến hợp lệ nào khác. Ở cuối định nghĩa của cấu trúc, trước dấu chấm phẩy cuối cùng, bạn có thể chỉ định một hoặc nhiều biến cấu trúc nhưng nó là tùy chọn. Đây là cách bạn khai báo cấu trúc Sách -

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
} book;

Truy cập thành viên cấu trúc

Để truy cập bất kỳ thành viên nào của một cấu trúc, chúng tôi sử dụng member access operator (.). Toán tử truy cập thành viên được mã hóa là dấu chấm giữa tên biến cấu trúc và thành viên cấu trúc mà chúng ta muốn truy cập. Bạn sẽ sử dụngstructtừ khóa để xác định các biến của kiểu cấu trúc. Sau đây là ví dụ để giải thích cách sử dụng cấu trúc:

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};
 
int main() {
   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = @"Objective-C Programming";
   Book1.author = @"Nuha Ali"; 
   Book1.subject = @"Objective-C Programming Tutorial";
   Book1.book_id = 6495407;

   /* book 2 specification */
   Book2.title = @"Telecom Billing";
   Book2.author = @"Zara Ali";
   Book2.subject = @"Telecom Billing Tutorial";
   Book2.book_id = 6495700;
 
   /* print Book1 info */
   NSLog(@"Book 1 title : %@\n", Book1.title);
   NSLog(@"Book 1 author : %@\n", Book1.author);
   NSLog(@"Book 1 subject : %@\n", Book1.subject);
   NSLog(@"Book 1 book_id : %d\n", Book1.book_id);

   /* print Book2 info */
   NSLog(@"Book 2 title : %@\n", Book2.title);
   NSLog(@"Book 2 author : %@\n", Book2.author);
   NSLog(@"Book 2 subject : %@\n", Book2.subject);
   NSLog(@"Book 2 book_id : %d\n", Book2.book_id);

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 04:20:07.947 demo[20591] Book 1 title : Objective-C Programming
2013-09-14 04:20:07.947 demo[20591] Book 1 author : Nuha Ali
2013-09-14 04:20:07.947 demo[20591] Book 1 subject : Objective-C Programming Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 1 book_id : 6495407
2013-09-14 04:20:07.947 demo[20591] Book 2 title : Telecom Billing
2013-09-14 04:20:07.947 demo[20591] Book 2 author : Zara Ali
2013-09-14 04:20:07.947 demo[20591] Book 2 subject : Telecom Billing Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 2 book_id : 6495700

Cấu trúc dưới dạng đối số hàm

Bạn có thể truyền một cấu trúc như một đối số của hàm theo cách tương tự như khi bạn truyền bất kỳ biến hoặc con trỏ nào khác. Bạn sẽ truy cập các biến cấu trúc theo cách tương tự như bạn đã truy cập trong ví dụ trên -

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};

@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books) book ;
@end

@implementation SampleClass 

- (void) printBook:( struct Books) book {
   NSLog(@"Book title : %@\n", book.title);
   NSLog(@"Book author : %@\n", book.author);
   NSLog(@"Book subject : %@\n", book.subject);
   NSLog(@"Book book_id : %d\n", book.book_id);
}

@end

int main() {
   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = @"Objective-C Programming";
   Book1.author = @"Nuha Ali"; 
   Book1.subject = @"Objective-C Programming Tutorial";
   Book1.book_id = 6495407;

   /* book 2 specification */
   Book2.title = @"Telecom Billing";
   Book2.author = @"Zara Ali";
   Book2.subject = @"Telecom Billing Tutorial";
   Book2.book_id = 6495700;
 
   SampleClass *sampleClass = [[SampleClass alloc]init];
   /* print Book1 info */
   [sampleClass printBook: Book1];

   /* Print Book2 info */
   [sampleClass printBook: Book2];

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 04:34:45.725 demo[8060] Book title : Objective-C Programming
2013-09-14 04:34:45.725 demo[8060] Book author : Nuha Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Objective-C Programming Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495407
2013-09-14 04:34:45.725 demo[8060] Book title : Telecom Billing
2013-09-14 04:34:45.725 demo[8060] Book author : Zara Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Telecom Billing Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495700

Con trỏ đến cấu trúc

Bạn có thể xác định con trỏ đến cấu trúc theo cách tương tự như bạn định nghĩa con trỏ cho bất kỳ biến nào khác như sau:

struct Books *struct_pointer;

Bây giờ, bạn có thể lưu trữ địa chỉ của một biến cấu trúc trong biến con trỏ được xác định ở trên. Để tìm địa chỉ của một biến cấu trúc, hãy đặt toán tử & trước tên của cấu trúc như sau:

struct_pointer = &Book1;

Để truy cập các thành viên của một cấu trúc bằng cách sử dụng con trỏ đến cấu trúc đó, bạn phải sử dụng toán tử -> như sau:

struct_pointer->title;

Hãy để chúng tôi viết lại ví dụ trên bằng cách sử dụng con trỏ cấu trúc, hy vọng điều này sẽ dễ dàng cho bạn hiểu khái niệm -

#import <Foundation/Foundation.h>

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
};

@interface SampleClass:NSObject
/* function declaration */
- (void) printBook:( struct Books *) book ;
@end

@implementation SampleClass 
- (void) printBook:( struct Books *) book {
   NSLog(@"Book title : %@\n", book->title);
   NSLog(@"Book author : %@\n", book->author);
   NSLog(@"Book subject : %@\n", book->subject);
   NSLog(@"Book book_id : %d\n", book->book_id);
}

@end

int main() {
   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = @"Objective-C Programming";
   Book1.author = @"Nuha Ali"; 
   Book1.subject = @"Objective-C Programming Tutorial";
   Book1.book_id = 6495407;

   /* book 2 specification */
   Book2.title = @"Telecom Billing";
   Book2.author = @"Zara Ali";
   Book2.subject = @"Telecom Billing Tutorial";
   Book2.book_id = 6495700;
 
   SampleClass *sampleClass = [[SampleClass alloc]init];
   /* print Book1 info by passing address of Book1 */
   [sampleClass printBook:&Book1];

   /* print Book2 info by passing address of Book2 */
   [sampleClass printBook:&Book2];

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 04:38:13.942 demo[20745] Book title : Objective-C Programming
2013-09-14 04:38:13.942 demo[20745] Book author : Nuha Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Objective-C Programming Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495407
2013-09-14 04:38:13.942 demo[20745] Book title : Telecom Billing
2013-09-14 04:38:13.942 demo[20745] Book author : Zara Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Telecom Billing Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495700

Trường bit

Trường Bit cho phép đóng gói dữ liệu trong một cấu trúc. Điều này đặc biệt hữu ích khi bộ nhớ hoặc lưu trữ dữ liệu ở mức cao. Ví dụ điển hình -

  • Đóng gói một số đối tượng thành một từ máy. ví dụ: cờ 1 bit có thể được nén chặt.

  • Đọc các định dạng tệp bên ngoài - các định dạng tệp không chuẩn có thể được đọc trong. Ví dụ: số nguyên 9 bit.

Objective-C cho phép chúng ta thực hiện điều này trong một định nghĩa cấu trúc bằng cách đặt: độ dài bit sau biến. Ví dụ -

struct packed_struct {
   unsigned int f1:1;
   unsigned int f2:1;
   unsigned int f3:1;
   unsigned int f4:1;
   unsigned int type:4;
   unsigned int my_int:9;
} pack;

Ở đây, pack_struct chứa 6 thành viên: Bốn cờ 1 bit f1..f3, loại 4 bit và my_int 9 bit.

Objective-C tự động đóng gói các trường bit ở trên một cách nhỏ gọn nhất có thể, với điều kiện độ dài tối đa của trường nhỏ hơn hoặc bằng độ dài từ số nguyên của máy tính. Nếu không đúng như vậy, thì một số trình biên dịch có thể cho phép chồng chéo bộ nhớ cho các trường trong khi trình biên dịch khác sẽ lưu trường tiếp theo trong từ tiếp theo.

Các Objective-C Preprocessorkhông phải là một phần của trình biên dịch, nhưng là một bước riêng biệt trong quá trình biên dịch. Nói một cách dễ hiểu, Objective-C Preprocessor chỉ là một công cụ thay thế văn bản và nó hướng dẫn trình biên dịch thực hiện xử lý trước cần thiết trước khi biên dịch thực sự. Chúng tôi sẽ gọi Bộ tiền xử lý Objective-C là OCPP.

Tất cả các lệnh tiền xử lý bắt đầu bằng ký hiệu bảng Anh (#). Nó phải là ký tự không trống đầu tiên và để dễ đọc, chỉ thị tiền xử lý phải bắt đầu trong cột đầu tiên. Phần sau liệt kê tất cả các chỉ thị tiền xử lý quan trọng -

Sr.No. Chỉ thị & Mô tả
1

#define

Thay thế macro bộ xử lý trước

2

#include

Chèn một tiêu đề cụ thể từ một tệp khác

3

#undef

Hoàn tác xác định macro bộ xử lý trước

4

#ifdef

Trả về true nếu macro này được xác định

5

#ifndef

Trả về true nếu macro này không được xác định

6

#if

Kiểm tra xem điều kiện thời gian biên dịch có đúng không

7

#else

Giải pháp thay thế cho #if

số 8

#elif

#else an #if trong một câu lệnh

9

#endif

Kết thúc điều kiện tiền xử lý

10

#error

In thông báo lỗi trên stderr

11

#pragma

Đưa ra các lệnh đặc biệt cho trình biên dịch bằng phương pháp chuẩn hóa

Ví dụ về bộ tiền xử lý

Phân tích các ví dụ sau để hiểu các lệnh khác nhau.

#define MAX_ARRAY_LENGTH 20

Lệnh này yêu cầu OCPP thay thế các trường hợp MAX_ARRAY_LENGTH bằng 20. Sử dụng #define cho các hằng số để tăng khả năng đọc.

#import <Foundation/Foundation.h>
#include "myheader.h"

Các chỉ thị này yêu cầu OCPP có được nền tảng.h từ Foundation Frameworkvà thêm văn bản vào tệp nguồn hiện tại. Dòng tiếp theo cho biết OCPP lấymyheader.h từ thư mục cục bộ và thêm nội dung vào tệp nguồn hiện tại.

#undef  FILE_SIZE
#define FILE_SIZE 42

Điều này yêu cầu OCPP hủy xác định FILE_SIZE hiện có và xác định nó là 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

Điều này yêu cầu OCPP chỉ xác định MESSAGE nếu MESSAGE chưa được xác định.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Điều này yêu cầu OCPP thực hiện quy trình với các câu lệnh kèm theo nếu DEBUG được xác định. Điều này rất hữu ích nếu bạn chuyển cờ -DDEBUG cho trình biên dịch gcc tại thời điểm biên dịch. Điều này sẽ xác định Gỡ lỗi, vì vậy bạn có thể bật và tắt gỡ lỗi ngay lập tức trong quá trình biên dịch.

Macro được xác định trước

ANSI C xác định một số macro. Mặc dù mỗi cái đều có sẵn để bạn sử dụng trong lập trình, bạn không nên sửa đổi trực tiếp các macro được xác định trước.

Sr.No. Macro & Mô tả
1

__DATE__

Ngày hiện tại dưới dạng một ký tự ở định dạng "MMM DD YYYY"

2

__TIME__

Thời gian hiện tại dưới dạng một ký tự ở định dạng "HH: MM: SS"

3

__FILE__

Điều này chứa tên tệp hiện tại dưới dạng một chuỗi ký tự.

4

__LINE__

Điều này chứa số dòng hiện tại dưới dạng hằng số thập phân.

5

__STDC__

Được xác định là 1 khi trình biên dịch tuân thủ tiêu chuẩn ANSI.

Hãy thử ví dụ sau:

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"File :%s\n", __FILE__ );
   NSLog(@"Date :%s\n", __DATE__ );
   NSLog(@"Time :%s\n", __TIME__ );
   NSLog(@"Line :%d\n", __LINE__ );
   NSLog(@"ANSI :%d\n", __STDC__ );
   
   return 0;
}

Khi mã trên trong một tệp main.m được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1

Nhà điều hành tiền xử lý

Bộ tiền xử lý Objective-C cung cấp các toán tử sau để giúp bạn tạo macro -

Tiếp tục Macro (\)

Một macro thường phải được chứa trên một dòng. Toán tử tiếp tục macro được sử dụng để tiếp tục một macro quá dài đối với một dòng. Ví dụ -

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

Kích thước chuỗi (#)

Toán tử chuỗi ký tự hoặc ký hiệu số ('#'), khi được sử dụng trong định nghĩa macro, chuyển đổi một tham số macro thành một hằng số chuỗi. Toán tử này chỉ có thể được sử dụng trong macro có đối số hoặc danh sách tham số được chỉ định. Ví dụ -

#import <Foundation/Foundation.h>

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!

Dán mã thông báo (##)

Toán tử dán mã thông báo (##) trong định nghĩa macro kết hợp hai đối số. Nó cho phép hai mã thông báo riêng biệt trong định nghĩa macro được kết hợp thành một mã thông báo duy nhất. Ví dụ -

#import <Foundation/Foundation.h>

#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 05:48:14.859 demo[20683] token34 = 40

Nó đã xảy ra như thế nào, bởi vì ví dụ này dẫn đến kết quả thực tế sau đây từ bộ tiền xử lý -

NSLog (@"token34 = %d", token34);

Ví dụ này cho thấy sự ghép nối của mã thông báo ## n vào mã thông báo34 và ở đây chúng tôi đã sử dụng cả hai stringizetoken-pasting.

Toán tử () được xác định

Bộ tiền xử lý definedtoán tử được sử dụng trong các biểu thức hằng để xác định xem một số nhận dạng có được xác định bằng cách sử dụng #define hay không. Nếu định danh được chỉ định được xác định, giá trị là true (khác 0). Nếu ký hiệu không được xác định, giá trị là false (không). Toán tử đã định nghĩa được chỉ định như sau:

#import <Foundation/Foundation.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   NSLog(@"Here is the message: %s\n", MESSAGE);  
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!

Macro được tham số hóa

Một trong những chức năng mạnh mẽ của OCPP là khả năng mô phỏng các chức năng bằng cách sử dụng macro được tham số hóa. Ví dụ: chúng ta có thể có một số mã để bình phương một số như sau:

int square(int x) {
   return x * x;
}

Chúng ta có thể viết lại đoạn mã trên bằng macro như sau:

#define square(x) ((x) * (x))

Các macro có đối số phải được xác định bằng cách sử dụng #definechỉ thị trước khi chúng có thể được sử dụng. Danh sách đối số được đặt trong dấu ngoặc đơn và phải ngay sau tên macro. Không được phép có dấu cách giữa tên macro và dấu ngoặc đơn mở. Ví dụ -

#import <Foundation/Foundation.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20

Ngôn ngữ lập trình Objective-C cung cấp một từ khóa có tên là typedef, mà bạn có thể sử dụng để đặt tên mới cho một loại. Sau đây là một ví dụ để xác định một thuật ngữBYTE cho các số một byte -

typedef unsigned char BYTE;

Sau định nghĩa kiểu này, số nhận dạng BYTE có thể được sử dụng làm chữ viết tắt cho kiểu unsigned char, for example:.

BYTE  b1, b2;

Theo quy ước, chữ hoa được sử dụng cho các định nghĩa này để nhắc nhở người dùng rằng tên kiểu thực sự là một chữ viết tắt tượng trưng, ​​nhưng bạn có thể sử dụng chữ thường, như sau:

typedef unsigned char byte;

Bạn có thể dùng typedefđể đặt tên cho kiểu dữ liệu do người dùng xác định. Ví dụ: bạn có thể sử dụng typedef với cấu trúc để xác định kiểu dữ liệu mới và sau đó sử dụng kiểu dữ liệu đó để xác định trực tiếp các biến cấu trúc như sau:

#import <Foundation/Foundation.h>

typedef struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int book_id;
} Book;
 
int main() {
   Book book;
   book.title = @"Objective-C Programming";
   book.author = @"TutorialsPoint";
   book.subject = @"Programming tutorial";
   book.book_id = 100;
   
   NSLog( @"Book title : %@\n", book.title);
   NSLog( @"Book author : %@\n", book.author);
   NSLog( @"Book subject : %@\n", book.subject);
   NSLog( @"Book Id : %d\n", book.book_id);

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-12 12:21:53.745 demo[31183] Book title : Objective-C Programming
2013-09-12 12:21:53.745 demo[31183] Book author : TutorialsPoint
2013-09-12 12:21:53.745 demo[31183] Book subject : Programming tutorial
2013-09-12 12:21:53.745 demo[31183] Book Id : 100

typedef so với #define

Các #define là một chỉ thị Objective-C, cũng được sử dụng để xác định bí danh cho các kiểu dữ liệu khác nhau tương tự như typedef nhưng với những khác biệt sau -

  • Các typedef chỉ giới hạn trong việc đặt tên tượng trưng cho các loại trong khi #define cũng có thể được sử dụng để xác định bí danh cho các giá trị, chẳng hạn như bạn có thể xác định 1 là MỘT, v.v.

  • Các typedef sự diễn giải được thực hiện bởi trình biên dịch trong đó #define các câu lệnh được xử lý bởi bộ xử lý trước.

Sau đây là cách sử dụng đơn giản nhất của #define -

#import <Foundation/Foundation.h>
 
#define TRUE  1
#define FALSE 0
 
int main( ) {
   NSLog( @"Value of TRUE : %d\n", TRUE);
   NSLog( @"Value of FALSE : %d\n", FALSE);

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-12 12:23:37.993 demo[5160] Value of TRUE : 1
2013-09-12 12:23:37.994 demo[5160] Value of FALSE : 0

Ép kiểu là một cách để chuyển đổi một biến từ kiểu dữ liệu này sang kiểu dữ liệu khác. Ví dụ: nếu bạn muốn lưu trữ một giá trị dài thành một số nguyên đơn giản thì bạn có thể nhập cast long thành int. Bạn có thể chuyển đổi các giá trị từ loại này sang loại khác một cách rõ ràng bằng cách sử dụngcast operator như sau -

(type_name) expression

Trong Objective-C, chúng tôi thường sử dụng CGFloat để thực hiện hoạt động dấu phẩy động, được bắt nguồn từ kiểu float cơ bản trong trường hợp 32-bit và kép trong trường hợp 64-bit. Hãy xem xét ví dụ sau trong đó toán tử ép kiểu khiến phép chia một biến số nguyên cho một biến số nguyên khác được thực hiện như một phép toán dấu phẩy động:

#import <Foundation/Foundation.h>

int main() {
   int sum = 17, count = 5;
   CGFloat mean;

   mean = (CGFloat) sum / count;
   NSLog(@"Value of mean : %f\n", mean );

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-11 01:35:40.047 demo[20634] Value of mean : 3.400000

Cần lưu ý ở đây rằng toán tử ép kiểu được ưu tiên hơn phép chia, vì vậy giá trị của sum lần đầu tiên được chuyển đổi thành loại double và cuối cùng nó được chia cho số đếm tạo ra một giá trị gấp đôi.

Chuyển đổi kiểu có thể là ẩn được trình biên dịch thực hiện tự động hoặc nó có thể được chỉ định rõ ràng thông qua việc sử dụng cast operator. Việc sử dụng toán tử ép kiểu được coi là thực hành tốt khi cần chuyển đổi kiểu.

Quảng cáo số nguyên

Thăng hạng số nguyên là quá trình mà các giá trị của kiểu số nguyên "nhỏ hơn" int hoặc là unsigned int được chuyển đổi thành int hoặc là unsigned int. Hãy xem xét một ví dụ về việc thêm một ký tự trong một int -

#import <Foundation/Foundation.h>

int main() {
   int  i = 17;
   char c = 'c';  /* ascii value is 99 */
   int sum;

   sum = i + c;
   NSLog(@"Value of sum : %d\n", sum );

   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-11 01:38:28.492 demo[980] Value of sum : 116

Ở đây, giá trị của sum là 116 vì trình biên dịch đang thực hiện việc thăng hạng số nguyên và chuyển đổi giá trị của 'c' thành ascii trước khi thực hiện thao tác cộng thực tế.

Chuyển đổi số học thông thường

Các usual arithmetic conversionsđược thực hiện ngầm định để ép các giá trị của chúng trong một kiểu chung. Trình biên dịch đầu tiên thực hiện thăng hạng số nguyên , nếu các toán hạng vẫn có các kiểu khác nhau thì chúng được chuyển đổi thành kiểu xuất hiện cao nhất trong hệ thống phân cấp sau:

Các phép chuyển đổi số học thông thường không được thực hiện cho các toán tử gán, cũng không cho các toán tử logic && và ||. Hãy lấy ví dụ sau để hiểu khái niệm -

#import <Foundation/Foundation.h>

int main() {
   int  i = 17;
   char c = 'c';  /* ascii value is 99 */
   CGFloat sum;

   sum = i + c;
   NSLog(@"Value of sum : %f\n", sum );
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-11 01:41:39.192 demo[15351] Value of sum : 116.000000

Ở đây, có thể hiểu đơn giản rằng c đầu tiên được chuyển đổi thành số nguyên nhưng vì giá trị cuối cùng là float, vì vậy việc chuyển đổi số học thông thường được áp dụng và trình biên dịch chuyển đổi i và c thành float và thêm chúng vào để tạo ra kết quả float.

Phương pháp NSLog

Để in nhật ký, chúng tôi sử dụng phương thức NSLog trong ngôn ngữ lập trình Objective-C mà chúng tôi đã sử dụng ngay từ ví dụ Hello World.

Chúng ta hãy xem một đoạn mã đơn giản có in dòng chữ "Hello World" -

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Hello, World! \n");
   return 0;
}

Bây giờ, khi chúng ta biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả sau.

2013-09-16 00:32:50.888 demo[16669] Hello, World!

Tắt nhật ký trong ứng dụng Trực tiếp

Vì NSLog mà chúng tôi sử dụng trong ứng dụng của mình, nó sẽ được in trong nhật ký của thiết bị và việc in nhật ký trong một bản dựng trực tiếp là không tốt. Do đó, chúng tôi sử dụng định nghĩa kiểu để in nhật ký và chúng tôi có thể sử dụng chúng như hình dưới đây.

#import <Foundation/Foundation.h>

#if DEBUG == 0
#define DebugLog(...)
#elif DEBUG == 1
#define DebugLog(...) NSLog(__VA_ARGS__)
#endif

int main() {
   DebugLog(@"Debug log, our custom addition gets \
   printed during debug only" );
   NSLog(@"NSLog gets printed always" );     
   return 0;
}

Bây giờ, khi chúng ta biên dịch và chạy chương trình ở chế độ gỡ lỗi, chúng ta sẽ nhận được kết quả sau.

2013-09-11 02:47:07.723 demo[618] Debug log, our custom addition gets printed during debug only
2013-09-11 02:47:07.723 demo[618] NSLog gets printed always

Bây giờ, khi chúng ta biên dịch và chạy chương trình ở chế độ phát hành, chúng ta sẽ nhận được kết quả sau.

2013-09-11 02:47:45.248 demo[3158] NSLog gets printed always

Trong lập trình Objective-C, xử lý lỗi được cung cấp với lớp NSError có sẵn trong Foundation framework.

Một đối tượng NSError đóng gói thông tin lỗi phong phú hơn và có thể mở rộng hơn khả năng chỉ sử dụng mã lỗi hoặc chuỗi lỗi. Các thuộc tính cốt lõi của đối tượng NSError là miền lỗi (được biểu thị bằng một chuỗi), mã lỗi dành riêng cho miền và từ điển thông tin người dùng chứa thông tin cụ thể về ứng dụng.

NSError

Các chương trình Objective-C sử dụng các đối tượng NSError để truyền tải thông tin về các lỗi thời gian chạy mà người dùng cần được thông báo. Trong hầu hết các trường hợp, một chương trình hiển thị thông tin lỗi này trong hộp thoại hoặc trang tính. Nhưng nó cũng có thể diễn giải thông tin và yêu cầu người dùng cố gắng khôi phục lỗi hoặc cố gắng tự sửa lỗi

Đối tượng NSError bao gồm -

  • Domain - Miền lỗi có thể là một trong các miền NSError được xác định trước hoặc một chuỗi tùy ý mô tả miền tùy chỉnh và miền không được bằng 0.

  • Code - Mã lỗi cho lỗi.

  • User Info - Từ điển userInfo cho lỗi và userInfo có thể là 0.

Ví dụ sau cho thấy cách tạo lỗi tùy chỉnh

NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to complete the process", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
NSError *error = [NSError errorWithDomain:domain code:-101 userInfo:userInfo];

Đây là mã hoàn chỉnh của mẫu lỗi ở trên được chuyển làm tham chiếu đến một con trỏ -

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr;
@end

@implementation SampleClass

-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr {
   if(id == 1) {
      return @"Employee Test Name";
   } else {
      NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
      NSString *desc =@"Unable to complete the process";
      NSDictionary *userInfo = [[NSDictionary alloc] 
      initWithObjectsAndKeys:desc,
      @"NSLocalizedDescriptionKey",NULL];  
      *errorPtr = [NSError errorWithDomain:domain code:-101 
      userInfo:userInfo];
      return @"";
   }
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   SampleClass *sampleClass = [[SampleClass alloc]init];
   NSError *error = nil;
   NSString *name1 = [sampleClass getEmployeeNameForID:1 withError:&error];
  
   if(error) {
      NSLog(@"Error finding Name1: %@",error);
   } else {
      NSLog(@"Name1: %@",name1);
   }
   
   error = nil;
   NSString *name2 = [sampleClass getEmployeeNameForID:2 withError:&error];

   if(error) {
      NSLog(@"Error finding Name2: %@",error);
   } else {
      NSLog(@"Name2: %@",name2);
   }

   [pool drain];
   return 0; 
}

Trong ví dụ trên, chúng tôi trả về tên nếu id là 1, nếu không, chúng tôi đặt đối tượng lỗi do người dùng xác định.

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-14 18:01:00.809 demo[27632] Name1: Employee Test Name
2013-09-14 18:01:00.809 demo[27632] Error finding Name2: Unable to complete the process

Có thể chuyển một số giá trị từ dòng lệnh vào các chương trình Objective-C của bạn khi chúng được thực thi. Các giá trị này được gọi làcommand line arguments và nhiều khi chúng rất quan trọng đối với chương trình của bạn, đặc biệt khi bạn muốn kiểm soát chương trình của mình từ bên ngoài thay vì mã hóa cứng các giá trị đó bên trong mã.

Các đối số dòng lệnh được xử lý bằng cách sử dụng các đối số của hàm main () trong đó argc đề cập đến số lượng đối số được truyền và argv[]là một mảng con trỏ, trỏ đến mỗi đối số được truyền vào chương trình. Sau đây là một ví dụ đơn giản, kiểm tra xem có bất kỳ đối số nào được cung cấp từ dòng lệnh hay không và thực hiện hành động tương ứng:

#import <Foundation/Foundation.h>

int main( int argc, char *argv[] ) {
   if( argc == 2 ) {
      NSLog(@"The argument supplied is %s\n", argv[1]);
   } else if( argc > 2 ) {
      NSLog(@"Too many arguments supplied.\n");
   } else {
      NSLog(@"One argument expected.\n");
   }
}

Khi đoạn mã trên được biên dịch và thực thi với một đối số, chẳng hạn như "đang thử nghiệm", nó sẽ tạo ra kết quả như sau.

2013-09-13 03:01:17.333 demo[7640] The argument supplied is testing

Khi đoạn mã trên được biên dịch và thực thi với hai đối số, chẳng hạn như testing1 và testing2, nó sẽ tạo ra kết quả sau.

2013-09-13 03:01:18.333 demo[7640] Too many arguments supplied.

Khi đoạn mã trên được biên dịch và thực thi mà không truyền bất kỳ đối số nào, nó sẽ tạo ra kết quả sau.

2013-09-13 03:01:18.333 demo[7640] One argument expected

Cần lưu ý rằng argv[0] giữ tên của chính chương trình và argv[1]là một con trỏ đến đối số dòng lệnh đầu tiên được cung cấp và * argv [n] là đối số cuối cùng. Nếu không có đối số nào được cung cấp, thì argc sẽ là một, ngược lại nếu bạn chuyển một đối số thìargc được đặt ở 2.

Bạn chuyển tất cả các đối số dòng lệnh được phân tách bằng dấu cách, nhưng nếu bản thân đối số có khoảng trắng, thì bạn có thể chuyển các đối số như vậy bằng cách đặt chúng bên trong dấu ngoặc kép "" hoặc dấu nháy đơn ''. Hãy để chúng tôi viết lại ví dụ trên một lần nữa, nơi chúng tôi sẽ in tên chương trình và chúng tôi cũng chuyển đối số dòng lệnh bằng cách đặt bên trong dấu ngoặc kép:

#import <Foundation/Foundation.h>

int main( int argc, char *argv[] ) {
   NSLog(@"Program name %s\n", argv[0]);
 
   if( argc == 2 ) {
      NSLog(@"The argument supplied is %s\n", argv[1]);
   } else if( argc > 2 ) {
      NSLog(@"Too many arguments supplied.\n");
   } else {
      NSLog(@"One argument expected.\n");
   }
   
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi với một đối số duy nhất được phân tách bằng dấu cách nhưng bên trong dấu ngoặc kép cho biết "Testing1 Testing2", nó tạo ra kết quả sau.

2017-11-30 06:36:59.081 main[71010] Program name main
2017-11-30 06:36:59.082 main[71010] One argument expected.

Mục đích chính của ngôn ngữ lập trình Objective-C là thêm hướng đối tượng vào ngôn ngữ lập trình C và các lớp là tính năng trung tâm của Objective-C hỗ trợ lập trình hướng đối tượng và thường được gọi là kiểu do người dùng định nghĩa.

Một lớp được sử dụng để chỉ định dạng của một đối tượng và nó kết hợp biểu diễn dữ liệu và các phương thức để thao tác dữ liệu đó thành một gói gọn gàng. Dữ liệu và phương thức trong một lớp được gọi là thành viên của lớp.

Đặc điểm Objective-C

  • Lớp được định nghĩa trong hai phần khác nhau, cụ thể là @interface@implementation.

  • Hầu hết mọi thứ đều ở dạng vật thể.

  • Đối tượng nhận thông điệp và đối tượng thường được gọi là người nhận.

  • Các đối tượng chứa các biến thể hiện.

  • Các đối tượng và biến cá thể có phạm vi.

  • Các lớp ẩn hiện thực của một đối tượng.

  • Thuộc tính được sử dụng để cung cấp quyền truy cập vào các biến cá thể của lớp trong các lớp khác.

Định nghĩa Lớp Objective-C

Khi bạn xác định một lớp, bạn xác định một bản thiết kế cho một kiểu dữ liệu. Điều này không thực sự xác định bất kỳ dữ liệu nào, nhưng nó xác định ý nghĩa của tên lớp, nghĩa là, một đối tượng của lớp sẽ bao gồm những gì và những thao tác nào có thể được thực hiện trên một đối tượng như vậy.

Định nghĩa lớp bắt đầu bằng từ khóa @interfacetiếp theo là tên giao diện (lớp); và phần thân của lớp, được bao bởi một cặp dấu ngoặc nhọn. Trong Objective-C, tất cả các lớp đều bắt nguồn từ lớp cơ sở được gọi làNSObject. Nó là lớp cha của tất cả các lớp Objective-C. Nó cung cấp các phương thức cơ bản như cấp phát và khởi tạo bộ nhớ. Ví dụ: chúng tôi đã xác định kiểu dữ liệu Hộp bằng từ khóaclass như sau -

@interface Box:NSObject {
   //Instance variables
   double length;    // Length of a box
   double breadth;   // Breadth of a box
}
@property(nonatomic, readwrite) double height;  // Property

@end

Các biến cá thể là riêng tư và chỉ có thể truy cập được bên trong việc triển khai lớp.

Phân bổ và khởi tạo đối tượng Objective-C

Một lớp cung cấp bản thiết kế cho các đối tượng, vì vậy về cơ bản một đối tượng được tạo ra từ một lớp. Chúng ta khai báo các đối tượng của một lớp với kiểu khai báo giống hệt như chúng ta khai báo các biến kiểu cơ bản. Các câu lệnh sau khai báo hai đối tượng của lớp Box:

Box box1 = [[Box alloc]init];     // Create box1 object of type Box
Box box2 = [[Box alloc]init];     // Create box2 object of type Box

Cả hai đối tượng box1 và box2 sẽ có bản sao dữ liệu của riêng chúng.

Truy cập các thành viên dữ liệu

Các thuộc tính của các đối tượng của một lớp có thể được truy cập bằng cách sử dụng toán tử truy cập thành viên trực tiếp (.). Chúng ta hãy thử ví dụ sau để làm rõ mọi thứ -

#import <Foundation/Foundation.h>

@interface Box:NSObject {
   double length;    // Length of a box
   double breadth;   // Breadth of a box
   double height;    // Height of a box
}

@property(nonatomic, readwrite) double height;  // Property
-(double) volume;
@end

@implementation Box

@synthesize height; 

-(id)init {
   self = [super init];
   length = 1.0;
   breadth = 1.0;
   return self;
}

-(double) volume {
   return length*breadth*height;
}

@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 volume = 0.0;             // Store the volume of a box here
 
   // box 1 specification
   box1.height = 5.0; 

   // box 2 specification
   box2.height = 10.0;
  
   // volume of box 1
   volume = [box1 volume];
   NSLog(@"Volume of Box1 : %f", volume);
   
   // volume of box 2
   volume = [box2 volume];
   NSLog(@"Volume of Box2 : %f", volume);
   
   [pool drain];
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-22 21:25:33.314 ClassAndObjects[387:303] Volume of Box1 : 5.000000
2013-09-22 21:25:33.316 ClassAndObjects[387:303] Volume of Box2 : 10.000000

Tính chất

Các thuộc tính được giới thiệu trong Objective-C để đảm bảo rằng biến thể hiện của lớp có thể được truy cập bên ngoài lớp.

  • Thuộc tính bắt đầu bằng @property, đó là một từ khóa

  • Theo sau nó là các từ chỉ định truy cập, không có giải phẫu hoặc nguyên tử, ghi đọc hoặc chỉ đọc và mạnh, không an toàn_ không an toàn hoặc yếu. Điều này thay đổi tùy thuộc vào loại biến. Đối với bất kỳ loại con trỏ nào, chúng ta có thể sử dụng strong, secure_unretained hoặc yếu. Tương tự đối với các loại khác, chúng ta có thể sử dụng readwrite hoặc readonly.

  • Tiếp theo là kiểu dữ liệu của biến.

  • Cuối cùng, chúng ta có tên thuộc tính được kết thúc bằng dấu chấm phẩy.

  • Chúng ta có thể thêm câu lệnh tổng hợp trong lớp thực thi. Nhưng trong XCode mới nhất, phần tổng hợp được đảm nhận bởi XCode và bạn không cần bao gồm câu lệnh tổng hợp.

Nó chỉ có thể với các thuộc tính mà chúng ta có thể truy cập các biến cá thể của lớp. Trên thực tế, các phương thức getter và setter bên trong được tạo cho các thuộc tính.

Ví dụ: giả sử chúng ta có một thuộc tính @property (nonatomic ,readonly ) BOOL isDone. Dưới mui xe, có các setters và getters được tạo ra như hình dưới đây.

-(void)setIsDone(BOOL)isDone;
-(BOOL)isDone;

Một trong những khái niệm quan trọng nhất trong lập trình hướng đối tượng là tính kế thừa. Tính kế thừa cho phép chúng ta định nghĩa một lớp theo nghĩa của một lớp khác, giúp tạo và duy trì một ứng dụng dễ dàng hơn. Điều này cũng tạo cơ hội để sử dụng lại chức năng mã và thời gian thực hiện nhanh chóng.

Khi tạo một lớp, thay vì viết các thành viên dữ liệu hoàn toàn mới và các hàm thành viên, lập trình viên có thể chỉ định rằng lớp mới sẽ kế thừa các thành viên của một lớp hiện có. Lớp hiện có này được gọi làbase lớp và lớp mới được gọi là derived lớp học.

Ý tưởng kế thừa thực hiện is amối quan hệ. Ví dụ, động vật IS-A động vật có vú, động vật IS-A động vật có vú, do đó chó IS-A động vật cũng như vậy.

Các lớp cơ sở & có nguồn gốc

Objective-C chỉ cho phép kế thừa đa cấp, tức là nó có thể chỉ có một lớp cơ sở nhưng cho phép kế thừa đa cấp. Tất cả các lớp trong Objective-C đều có nguồn gốc từ lớp chaNSObject.

@interface derived-class: base-class

Xem xét một lớp cơ sở Person và lớp dẫn xuất của nó Employee như sau -

#import <Foundation/Foundation.h>
 
@interface Person : NSObject {
   NSString *personName;
   NSInteger personAge;
}

- (id)initWithName:(NSString *)name andAge:(NSInteger)age;
- (void)print;

@end

@implementation Person

- (id)initWithName:(NSString *)name andAge:(NSInteger)age {
   personName = name;
   personAge = age;
   return self;
}

- (void)print {
   NSLog(@"Name: %@", personName);
   NSLog(@"Age: %ld", personAge);
}

@end

@interface Employee : Person {
   NSString *employeeEducation;
}

- (id)initWithName:(NSString *)name andAge:(NSInteger)age 
  andEducation:(NSString *)education;
- (void)print;
@end

@implementation Employee

- (id)initWithName:(NSString *)name andAge:(NSInteger)age 
   andEducation: (NSString *)education {
      personName = name;
      personAge = age;
      employeeEducation = education;
      return self;
   }

- (void)print {
   NSLog(@"Name: %@", personName);
   NSLog(@"Age: %ld", personAge);
   NSLog(@"Education: %@", employeeEducation);
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];        
   NSLog(@"Base class Person Object");
   Person *person = [[Person alloc]initWithName:@"Raj" andAge:5];
   [person print];
   NSLog(@"Inherited Class Employee Object");
   Employee *employee = [[Employee alloc]initWithName:@"Raj" 
   andAge:5 andEducation:@"MBA"];
   [employee print];        
   [pool drain];
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-22 21:20:09.842 Inheritance[349:303] Base class Person Object
2013-09-22 21:20:09.844 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.844 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.845 Inheritance[349:303] Inherited Class Employee Object
2013-09-22 21:20:09.845 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.846 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.846 Inheritance[349:303] Education: MBA

Kiểm soát truy cập và kế thừa

Một lớp dẫn xuất có thể truy cập tất cả các thành viên riêng của lớp cơ sở của nó nếu nó được định nghĩa trong lớp giao diện, nhưng nó không thể truy cập các thành viên riêng được xác định trong tệp thực thi.

Chúng tôi có thể tóm tắt các kiểu truy cập khác nhau tùy theo người có thể truy cập chúng theo cách sau:

Một lớp dẫn xuất kế thừa tất cả các phương thức và biến của lớp cơ sở với các ngoại lệ sau:

  • Không thể truy cập các biến được khai báo trong tệp triển khai với sự trợ giúp của phần mở rộng.

  • Không thể truy cập các phương thức được khai báo trong tệp triển khai với sự trợ giúp của phần mở rộng.

  • Trong trường hợp lớp kế thừa thực thi phương thức trong lớp cơ sở, thì phương thức trong lớp dẫn xuất được thực thi.

Từ polymorphismnghĩa là có nhiều hình thức. Thông thường, tính đa hình xảy ra khi có một hệ thống phân cấp của các lớp và chúng có liên quan với nhau bởi tính kế thừa.

Tính đa hình Objective-C có nghĩa là một lệnh gọi đến một hàm thành viên sẽ khiến một hàm khác được thực thi tùy thuộc vào loại đối tượng gọi hàm.

Hãy xem xét ví dụ, chúng ta có một lớp Shape cung cấp giao diện cơ bản cho tất cả các hình dạng. Hình vuông và Hình chữ nhật có nguồn gốc từ Hình dạng lớp cơ sở.

Chúng tôi có phương thức printArea sẽ hiển thị về tính năng OOP polymorphism.

#import <Foundation/Foundation.h>

@interface Shape : NSObject {
   CGFloat area;
}

- (void)printArea;
- (void)calculateArea;
@end

@implementation Shape
- (void)printArea {
   NSLog(@"The area is %f", area);
}

- (void)calculateArea {

}

@end

@interface Square : Shape {
   CGFloat length;
}

- (id)initWithSide:(CGFloat)side;
- (void)calculateArea;

@end

@implementation Square
- (id)initWithSide:(CGFloat)side {
   length = side;
   return self;
}

- (void)calculateArea {
   area = length * length;
}

- (void)printArea {
   NSLog(@"The area of square is %f", area);
}

@end

@interface Rectangle : Shape {
   CGFloat length;
   CGFloat breadth;
}

- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth;
@end

@implementation Rectangle
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth {
   length = rLength;
   breadth = rBreadth;
   return self;
}

- (void)calculateArea {
   area = length * breadth;
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   Shape *square = [[Square alloc]initWithSide:10.0];
   [square calculateArea];
   [square printArea];
   Shape *rect = [[Rectangle alloc]
   initWithLength:10.0 andBreadth:5.0];
   [rect calculateArea];
   [rect printArea];        
   [pool drain];
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-22 21:21:50.785 Polymorphism[358:303] The area of square is 100.000000
2013-09-22 21:21:50.786 Polymorphism[358:303] The area is 50.000000

Trong ví dụ trên, dựa trên tính khả dụng của phương thức CalculArea và printArea, phương thức trong lớp cơ sở hoặc lớp dẫn xuất được thực thi.

Tính đa hình xử lý việc chuyển đổi các phương thức giữa lớp cơ sở và lớp dẫn xuất dựa trên việc triển khai phương thức của hai lớp.

Tất cả các chương trình Objective-C đều bao gồm hai yếu tố cơ bản sau:

  • Program statements (code) - Đây là một phần của chương trình thực hiện các hành động và chúng được gọi là các phương thức.

  • Program data - Dữ liệu là thông tin của chương trình bị ảnh hưởng bởi các chức năng của chương trình.

Đóng gói là một khái niệm Lập trình hướng đối tượng liên kết dữ liệu và các chức năng thao tác với dữ liệu lại với nhau và điều đó giữ an toàn cho cả hai bên ngoài sự can thiệp và lạm dụng. Tính năng đóng gói dữ liệu đã dẫn đến khái niệm OOP quan trọng vềdata hiding.

Data encapsulation là một cơ chế gói dữ liệu và các chức năng sử dụng chúng, và data abstraction là một cơ chế chỉ để lộ các giao diện và ẩn các chi tiết triển khai với người dùng.

Objective-C hỗ trợ các thuộc tính đóng gói và ẩn dữ liệu thông qua việc tạo ra các kiểu do người dùng xác định, được gọi là classes. Ví dụ -

@interface Adder : NSObject {
   NSInteger total;
}

- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;

@end

Biến tổng là private và chúng ta không thể truy cập từ bên ngoài lớp. Điều này có nghĩa là chúng chỉ có thể được truy cập bởi các thành viên khác của lớp Adder chứ không phải bất kỳ phần nào khác trong chương trình của bạn. Đây là một cách để đạt được sự đóng gói.

Các phương thức bên trong tệp giao diện có thể truy cập được và có phạm vi công khai.

Có những phương pháp riêng tư, được viết với sự trợ giúp của extensions, mà chúng ta sẽ tìm hiểu trong các chương sắp tới.

Ví dụ về đóng gói dữ liệu

Bất kỳ chương trình Objective-C nào mà bạn triển khai một lớp với các biến thành viên công cộng và riêng tư là một ví dụ về đóng gói dữ liệu và trừu tượng hóa dữ liệu. Hãy xem xét ví dụ sau:

#import <Foundation/Foundation.h>

@interface Adder : NSObject {
   NSInteger total;
}

- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;

@end

@implementation Adder
-(id)initWithInitialNumber:(NSInteger)initialNumber {
   total = initialNumber;
   return self;
}

- (void)addNumber:(NSInteger)newNumber {
   total = total + newNumber;
}

- (NSInteger)getTotal {
   return total;
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];        
   Adder *adder = [[Adder alloc]initWithInitialNumber:10];
   [adder addNumber:5];
   [adder addNumber:4];
   
   NSLog(@"The total is %ld",[adder getTotal]);
   [pool drain];
   return 0;
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

2013-09-22 21:17:30.485 DataEncapsulation[317:303] The total is 19

Lớp trên cộng các số lại với nhau và trả về tổng. Các thành viên công cộngaddNumgetTotal là các giao diện với thế giới bên ngoài và người dùng cần biết chúng để sử dụng lớp. Thành viên riêngtotal là một cái gì đó ẩn với thế giới bên ngoài, nhưng cần thiết để lớp hoạt động bình thường.

Chiến lược thiết kế

Hầu hết chúng ta đã học được qua kinh nghiệm cay đắng để đặt các thành viên trong lớp ở chế độ riêng tư theo mặc định trừ khi chúng ta thực sự cần để lộ chúng. Điều đó thật tốtencapsulation.

Điều quan trọng là phải hiểu đóng gói dữ liệu vì nó là một trong những tính năng cốt lõi của tất cả các ngôn ngữ Lập trình hướng đối tượng (OOP) bao gồm Objective-C.

Đôi khi, bạn có thể thấy rằng bạn muốn mở rộng một lớp hiện có bằng cách thêm hành vi chỉ hữu ích trong một số trường hợp nhất định. Để thêm phần mở rộng như vậy vào các lớp hiện có, Objective-C cung cấpcategoriesextensions.

Nếu bạn cần thêm một phương thức vào một lớp hiện có, có lẽ, để thêm chức năng nhằm giúp bạn thực hiện điều gì đó dễ dàng hơn trong ứng dụng của mình, cách dễ nhất là sử dụng một danh mục.

Cú pháp để khai báo một danh mục sử dụng từ khóa @interface, giống như mô tả lớp Objective-C tiêu chuẩn, nhưng không chỉ ra bất kỳ sự kế thừa nào từ một lớp con. Thay vào đó, nó chỉ định tên của danh mục trong ngoặc đơn, như thế này:

@interface ClassName (CategoryName)

@end

Đặc điểm của thể loại

  • Một danh mục có thể được khai báo cho bất kỳ lớp nào, ngay cả khi bạn không có mã nguồn triển khai ban đầu.

  • Bất kỳ phương thức nào mà bạn khai báo trong một danh mục sẽ có sẵn cho tất cả các thể hiện của lớp gốc, cũng như bất kỳ lớp con nào của lớp gốc.

  • Trong thời gian chạy, không có sự khác biệt giữa phương thức được thêm bởi một danh mục và một phương thức được thực thi bởi lớp ban đầu.

Bây giờ, chúng ta hãy xem xét một triển khai danh mục mẫu. Hãy thêm một danh mục vào lớp Cacao NSString. Danh mục này sẽ giúp chúng tôi có thể thêm một phương thức mới getCopyRightString để giúp chúng tôi trả về chuỗi bản quyền. Nó được hiển thị bên dưới.

#import <Foundation/Foundation.h>

@interface NSString(MyAdditions)
+(NSString *)getCopyRightString;
@end

@implementation NSString(MyAdditions)

+(NSString *)getCopyRightString {
   return @"Copyright TutorialsPoint.com 2013";
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   NSString *copyrightString = [NSString getCopyRightString];
   NSLog(@"Accessing Category: %@",copyrightString);
   
   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-22 21:19:12.125 Categories[340:303] Accessing Category: Copyright TutorialsPoint.com 2013

Mặc dù bất kỳ phương thức nào được thêm bởi một danh mục đều có sẵn cho tất cả các phiên bản của lớp và các lớp con của nó, bạn sẽ cần nhập tệp tiêu đề danh mục trong bất kỳ tệp mã nguồn nào mà bạn muốn sử dụng các phương thức bổ sung, nếu không bạn sẽ gặp phải cảnh báo và lỗi trình biên dịch.

Trong ví dụ của chúng tôi, vì chúng tôi chỉ có một lớp duy nhất, chúng tôi chưa bao gồm bất kỳ tệp tiêu đề nào, trong trường hợp này, chúng tôi nên bao gồm các tệp tiêu đề như đã nói ở trên.

Trước khi bắt đầu về Posing trong Objective-C, tôi muốn thông báo với bạn rằng Posing đã được tuyên bố là không còn được dùng trong Mac OS X 10.5 và nó sẽ không có sẵn để sử dụng sau đó. Vì vậy, đối với những người không quan tâm đến các phương pháp không dùng nữa có thể bỏ qua chương này.

Objective-C cho phép một lớp thay thế hoàn toàn một lớp khác trong một chương trình. Lớp thay thế được cho là "đóng giả" lớp mục tiêu.

Đối với các phiên bản hỗ trợ tạo dáng, thay vào đó, tất cả các thông báo được gửi đến lớp đích sẽ được lớp tạo dáng nhận.

NSObject chứa phương thức poseAsClass: cho phép chúng ta thay thế lớp hiện có như đã nói ở trên.

Hạn chế trong tư thế

  • Một lớp chỉ có thể đóng vai trò là một trong các lớp cha trực tiếp hoặc gián tiếp của nó.

  • Lớp đặt ra không được xác định bất kỳ biến thể hiện mới nào không có trong lớp đích (mặc dù nó có thể định nghĩa hoặc ghi đè các phương thức).

  • Lớp mục tiêu có thể không nhận được bất kỳ tin nhắn nào trước khi đặt ra.

  • Một lớp đặt ra có thể gọi các phương thức được ghi đè thông qua siêu, do đó kết hợp việc thực hiện lớp đích.

  • Một lớp đặt ra có thể ghi đè các phương thức được xác định trong các danh mục.

#import <Foundation/Foundation.h>

@interface MyString : NSString

@end

@implementation MyString

- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement {
   NSLog(@"The Target string is %@",target);
   NSLog(@"The Replacement string is %@",replacement);
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   [MyString poseAsClass:[NSString class]];
   NSString *string = @"Test";
   [string stringByReplacingOccurrencesOfString:@"a" withString:@"c"];
   
   [pool drain];
   return 0;
}

Bây giờ khi chúng tôi biên dịch và chạy chương trình trong Mac OS X cũ hơn (V_10.5 trở xuống), chúng tôi sẽ nhận được kết quả sau.

2013-09-22 21:23:46.829 Posing[372:303] The Target string is a
2013-09-22 21:23:46.830 Posing[372:303] The Replacement string is c

Trong ví dụ trên, chúng tôi chỉ làm ô nhiễm phương thức gốc với việc triển khai của chúng tôi và điều này sẽ bị ảnh hưởng trong suốt tất cả các hoạt động của NSString với phương thức trên.

Phần mở rộng lớp mang một số điểm tương tự với một danh mục, nhưng nó chỉ có thể được thêm vào một lớp mà bạn có mã nguồn tại thời điểm biên dịch (lớp được biên dịch cùng lúc với phần mở rộng lớp).

Các phương thức được khai báo bởi phần mở rộng lớp được triển khai trong khối thực thi cho lớp gốc, vì vậy, ví dụ: bạn không thể khai báo phần mở rộng lớp trên một lớp khung, chẳng hạn như lớp Cocoa hoặc Cocoa Touch như NSString.

Phần mở rộng thực sự là danh mục không có tên danh mục. Nó thường được gọi làanonymous categories.

Cú pháp để khai báo tiện ích mở rộng sử dụng từ khóa @interface, giống như mô tả lớp Objective-C tiêu chuẩn, nhưng không chỉ ra bất kỳ sự kế thừa nào từ lớp con. Thay vào đó, nó chỉ thêm dấu ngoặc đơn, như hình dưới đây -

@interface ClassName ()

@end

Đặc điểm của phần mở rộng

  • Một phần mở rộng không thể được khai báo cho bất kỳ lớp nào, chỉ cho các lớp mà chúng ta có triển khai mã nguồn ban đầu.

  • Một phần mở rộng là thêm các phương thức riêng và các biến riêng chỉ dành riêng cho lớp.

  • Bất kỳ phương thức hoặc biến nào được khai báo bên trong các phần mở rộng đều không thể truy cập được ngay cả đối với các lớp kế thừa.

Ví dụ về tiện ích mở rộng

Hãy tạo một lớp SampleClass có phần mở rộng. Trong phần mở rộng, hãy có một biến private internalID.

Sau đó, hãy có một phương thức getExternalID trả về externalID sau khi xử lý InternalID.

Ví dụ được hiển thị bên dưới và điều này sẽ không hoạt động trên trình biên dịch trực tuyến.

#import <Foundation/Foundation.h>

@interface SampleClass : NSObject {
   NSString *name;
}

- (void)setInternalID;
- (NSString *)getExternalID;

@end

@interface SampleClass() {
   NSString *internalID;
}

@end

@implementation SampleClass

- (void)setInternalID {
   internalID = [NSString stringWithFormat: 
   @"UNIQUEINTERNALKEY%dUNIQUEINTERNALKEY",arc4random()%100];
}

- (NSString *)getExternalID {
   return [internalID stringByReplacingOccurrencesOfString: 
   @"UNIQUEINTERNALKEY" withString:@""];
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass setInternalID];
   NSLog(@"ExternalID: %@",[sampleClass getExternalID]);        
   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-22 21:18:31.754 Extensions[331:303] ExternalID: 51

Trong ví dụ trên, chúng ta có thể thấy rằng InternalID không được trả về trực tiếp. Ở đây, chúng tôi xóa UNIQUEINTERNALKEY và chỉ cung cấp giá trị còn lại cho phương thức getExternalID.

Ví dụ trên chỉ sử dụng một hoạt động chuỗi, nhưng nó có thể có nhiều tính năng như mã hóa / giải mã, v.v.

Objective-C cho phép bạn xác định các giao thức, khai báo các phương thức dự kiến ​​sẽ được sử dụng cho một tình huống cụ thể. Các giao thức được thực hiện trong các lớp phù hợp với giao thức.

Một ví dụ đơn giản sẽ là một lớp xử lý URL mạng, nó sẽ có một giao thức với các phương thức như phương thức ủy nhiệm processCompleted để tạo nội dung cho lớp gọi khi hoạt động tìm nạp URL mạng kết thúc.

Cú pháp của giao thức được hiển thị bên dưới.

@protocol ProtocolName
@required
// list of required methods
@optional
// list of optional methods
@end

Các phương pháp trong từ khóa @required phải được triển khai trong các lớp phù hợp với giao thức và các phương thức theo @optional từ khóa là tùy chọn để triển khai.

Đây là cú pháp cho lớp tuân theo giao thức

@interface MyClass : NSObject <MyProtocol>
...
@end

Điều này có nghĩa là bất kỳ phiên bản nào của MyClass sẽ không chỉ phản hồi các phương thức được khai báo cụ thể trong giao diện mà MyClass còn cung cấp các triển khai cho các phương thức được yêu cầu trong MyProtocol. Không cần phải khai báo lại các phương thức giao thức trong giao diện lớp - việc chấp nhận giao thức là đủ.

Nếu bạn cần một lớp để áp dụng nhiều giao thức, bạn có thể chỉ định chúng dưới dạng danh sách được phân tách bằng dấu phẩy. Chúng ta có một đối tượng ủy nhiệm chứa tham chiếu của đối tượng đang gọi thực thi giao thức.

Một ví dụ đã được biểu diễn ở dưới.

#import <Foundation/Foundation.h>

@protocol PrintProtocolDelegate
- (void)processCompleted;

@end

@interface PrintClass :NSObject {
   id delegate;
}

- (void) printDetails;
- (void) setDelegate:(id)newDelegate;
@end

@implementation PrintClass
- (void)printDetails {
   NSLog(@"Printing Details");
   [delegate processCompleted];
}

- (void) setDelegate:(id)newDelegate {
   delegate = newDelegate;
}

@end

@interface SampleClass:NSObject<PrintProtocolDelegate>
- (void)startAction;

@end

@implementation SampleClass
- (void)startAction {
   PrintClass *printClass = [[PrintClass alloc]init];
   [printClass setDelegate:self];
   [printClass printDetails];
}

-(void)processCompleted {
   NSLog(@"Printing Process Completed");
}

@end

int main(int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass startAction];
   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-22 21:15:50.362 Protocols[275:303] Printing Details
2013-09-22 21:15:50.364 Protocols[275:303] Printing Process Completed

Trong ví dụ trên, chúng ta đã thấy cách các phương thức hủy được gọi và thực thi. Nó bắt đầu bằng startAction, khi quá trình này hoàn tất, phương thức ủy nhiệm processCompleted được gọi để hoàn thành hoạt động.

Trong bất kỳ ứng dụng iOS hoặc Mac nào, chúng tôi sẽ không bao giờ triển khai chương trình mà không có người được ủy quyền. Vì vậy, điều quan trọng là chúng ta hiểu cách sử dụng các đại biểu. Các đối tượng đại diện nên sử dụng loại thuộc tính không an toàn_unretained để tránh rò rỉ bộ nhớ.

Liên kết động là xác định phương thức để gọi trong thời gian chạy thay vì tại thời điểm biên dịch. Ràng buộc động còn được gọi là ràng buộc muộn.

Trong Objective-C, tất cả các phương thức đều được giải quyết động trong thời gian chạy. Mã chính xác được thực thi được xác định bởi cả tên phương thức (bộ chọn) và đối tượng nhận.

Liên kết động cho phép đa hình. Ví dụ, hãy xem xét một tập hợp các đối tượng bao gồm Hình chữ nhật và Hình vuông. Mỗi đối tượng có một phương thức printArea triển khai riêng.

Trong đoạn mã sau, mã thực sẽ được thực thi bởi biểu thức [anObject printArea] được xác định trong thời gian chạy. Hệ thống thời gian chạy sử dụng bộ chọn cho phương thức chạy để xác định phương thức thích hợp trong bất kỳ lớp nào của anObject.

Chúng ta hãy xem một đoạn mã đơn giản giải thích ràng buộc động.

#import <Foundation/Foundation.h>

@interface Square:NSObject {
   float area;
}

- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end

@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
   area = side * side;
}

- (void)printArea {
   NSLog(@"The area of square is %f",area);
}

@end

@interface Rectangle:NSObject {
   float area;
}

- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth;
- (void)printArea;
@end

@implementation  Rectangle

- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth {
   area = length * breadth;
}

- (void)printArea {
   NSLog(@"The area of Rectangle is %f",area);
}

@end

int main() {
   Square *square = [[Square alloc]init];
   [square calculateAreaOfSide:10.0];
   
   Rectangle *rectangle = [[Rectangle alloc]init];
   [rectangle calculateAreaOfLength:10.0 andBreadth:5.0];
   
   NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
   id object1 = [shapes objectAtIndex:0];
   [object1 printArea];
   
   id object2 = [shapes objectAtIndex:1];
   [object2 printArea];
   
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-28 07:42:29.821 demo[4916] The area of square is 100.000000
2013-09-28 07:42:29.821 demo[4916] The area of Rectangle is 50.000000

Như bạn có thể thấy trong ví dụ trên, phương thức printArea được chọn động trong thời gian chạy. Nó là một ví dụ cho ràng buộc động và khá hữu ích trong nhiều tình huống khi xử lý các loại đối tượng tương tự.

Chúng ta có thể tạo lớp con bên trong một cụm lớp định nghĩa một lớp nhúng bên trong nó một đối tượng. Các đối tượng lớp này là các đối tượng hỗn hợp.

Vì vậy, bạn có thể tự hỏi một cụm lớp là gì. Vì vậy, trước tiên chúng ta sẽ xem một cụm lớp là gì.

Nhóm lớp

Các cụm lớp là một mẫu thiết kế mà khuôn khổ Foundation sử dụng rộng rãi. Các cụm lớp nhóm một số lớp con cụ thể riêng dưới một lớp cha trừu tượng công khai. Việc nhóm các lớp theo cách này đơn giản hóa kiến ​​trúc hiển thị công khai của khung hướng đối tượng mà không làm giảm tính phong phú về chức năng của nó. Các cụm lớp dựa trên mẫu thiết kế Abstract Factory.

Để đơn giản hơn, thay vì tạo nhiều lớp cho các hàm tương tự, chúng ta tạo một lớp duy nhất sẽ đảm nhận việc xử lý nó dựa trên giá trị của đầu vào.

Ví dụ, trong NSNumber, chúng ta có nhiều cụm lớp như char, int, bool, v.v. Chúng tôi nhóm tất cả chúng vào một lớp duy nhất để xử lý các hoạt động tương tự trong một lớp duy nhất. NSNumber thực sự bao bọc giá trị của các kiểu nguyên thủy này thành các đối tượng.

Vậy đối tượng tổng hợp chính xác là gì?

Bằng cách nhúng một đối tượng cụm riêng vào một đối tượng do chính chúng tôi thiết kế, chúng tôi tạo ra một đối tượng tổng hợp. Đối tượng tổng hợp này có thể dựa vào đối tượng cụm cho chức năng cơ bản của nó, chỉ chặn các thông báo mà đối tượng kết hợp muốn xử lý theo một cách cụ thể nào đó. Kiến trúc này làm giảm số lượng mã chúng ta phải viết và cho phép bạn tận dụng mã đã thử nghiệm do Foundation Framework cung cấp.

Điều này được giải thích trong hình sau.

Đối tượng tổng hợp phải tự khai báo là một lớp con của lớp cha trừu tượng của cụm. Là một lớp con, nó phải ghi đè các phương thức nguyên thủy của lớp cha. Nó cũng có thể ghi đè các phương thức dẫn xuất, nhưng điều này không cần thiết vì các phương thức dẫn xuất hoạt động thông qua các phương thức nguyên thủy.

Phương thức đếm của lớp NSArray là một ví dụ; việc thực hiện của đối tượng can thiệp của một phương thức mà nó ghi đè có thể đơn giản như:

- (unsigned)count  {
   return [embeddedObject count];
}

Trong ví dụ trên, đối tượng nhúng thực sự thuộc loại NSArray.

Ví dụ về đối tượng tổng hợp

Bây giờ để xem một ví dụ hoàn chỉnh, hãy xem ví dụ từ tài liệu của Apple được đưa ra bên dưới.

#import <Foundation/Foundation.h>

@interface ValidatingArray : NSMutableArray {
   NSMutableArray *embeddedArray;
}

+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;

@end

@implementation ValidatingArray
- init {
   self = [super init];
   if (self) {
      embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
   }
   return self;
}

+ validatingArray {
   return [[self alloc] init] ;
}

- (unsigned)count {
   return [embeddedArray count];
}

- objectAtIndex:(unsigned)index {
   return [embeddedArray objectAtIndex:index];
}

- (void)addObject:(id)object {
   if (object != nil) {
      [embeddedArray addObject:object];
   }
}

- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
   if (index <[embeddedArray count] && object != nil) {
      [embeddedArray replaceObjectAtIndex:index withObject:object];
   }
}

- (void)removeLastObject; {
   if ([embeddedArray count] > 0) {
      [embeddedArray removeLastObject];
   }
}

- (void)insertObject:(id)object atIndex:(unsigned)index; {
   if (object != nil) {
      [embeddedArray insertObject:object atIndex:index];
   }
}

- (void)removeObjectAtIndex:(unsigned)index; {
   if (index <[embeddedArray count]) {
      [embeddedArray removeObjectAtIndex:index];
   }
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   ValidatingArray *validatingArray = [ValidatingArray validatingArray];
   
   [validatingArray addObject:@"Object1"];
   [validatingArray addObject:@"Object2"];
   [validatingArray addObject:[NSNull null]];
   [validatingArray removeObjectAtIndex:2];
   NSString *aString = [validatingArray objectAtIndex:1];
   NSLog(@"The value at Index 1 is %@",aString);
   [pool drain];
   
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-28 22:03:54.294 demo[6247] The value at Index 1 is Object2

Trong ví dụ trên, chúng ta có thể thấy rằng việc xác thực một hàm của mảng sẽ không cho phép thêm các đối tượng rỗng, điều này sẽ dẫn đến sự cố trong trường hợp bình thường. Nhưng mảng xác thực của chúng tôi sẽ chăm sóc nó. Tương tự, mỗi phương thức trong mảng xác thực sẽ thêm các quá trình xác thực ngoài chuỗi hoạt động bình thường.

Nếu bạn tham khảo tài liệu của Apple, bạn có thể xem chi tiết về khuôn khổ Foundation như được đưa ra bên dưới.

Khuôn khổ Foundation định nghĩa một lớp cơ sở của các lớp Objective-C. Ngoài việc cung cấp một tập hợp các lớp đối tượng nguyên thủy hữu ích, nó giới thiệu một số mô hình xác định chức năng không được ngôn ngữ Objective-C bao hàm. Khuôn khổ Foundation được thiết kế với những mục tiêu này -

  • Cung cấp một tập hợp nhỏ các lớp tiện ích cơ bản.

  • Làm cho việc phát triển phần mềm dễ dàng hơn bằng cách đưa ra các quy ước nhất quán cho những thứ như phân bổ giao dịch.

  • Hỗ trợ chuỗi Unicode, độ bền đối tượng và phân phối đối tượng.

  • Cung cấp mức độ độc lập của hệ điều hành để nâng cao tính di động.

Khung được phát triển bởi NeXTStep, được Apple mua lại và các lớp nền tảng này đã trở thành một phần của Mac OS X và iOS.

Vì nó được phát triển bởi NeXTStep, nó có tiền tố lớp là "NS".

Chúng tôi đã sử dụng Foundation Framework trong tất cả các chương trình mẫu của chúng tôi. Gần như bắt buộc phải sử dụng Foundation Framework.

Nói chung, chúng tôi sử dụng một cái gì đó như #import <Foundation/NSString.h> để nhập một lớp Objective-C, nhưng để tránh nhập quá nhiều lớp, tất cả đều được nhập vào #import <Foundation/Foundation.h>.

NSObject là lớp cơ sở của tất cả các đối tượng bao gồm các lớp bộ công cụ nền tảng. Nó cung cấp các phương pháp quản lý bộ nhớ. Nó cũng cung cấp giao diện cơ bản cho hệ thống thời gian chạy và khả năng hoạt động như các đối tượng Objective-C. Nó không có bất kỳ lớp cơ sở nào và là gốc cho tất cả các lớp.

Các lớp nền tảng dựa trên chức năng

Sr.No. Loại vòng lặp & Mô tả
1 Lưu trữ dữ liệu

NSArray, NSDictionary và NSSet cung cấp khả năng lưu trữ cho các đối tượng Objective-C của bất kỳ lớp nào.

2 Văn bản và chuỗi

NSCharacterSet đại diện cho các nhóm ký tự khác nhau được sử dụng bởi các lớp NSString và NSScanner. Các lớp NSString đại diện cho các chuỗi văn bản và cung cấp các phương thức để tìm kiếm, kết hợp và so sánh các chuỗi. Đối tượng NSScanner được sử dụng để quét các số và từ từ một đối tượng NSString.

3 Ngày và giờ

Các lớp NSDate, NSTimeZone và NSCalendar lưu trữ thời gian và ngày tháng và đại diện cho thông tin lịch. Họ đưa ra các phương pháp tính toán chênh lệch ngày và giờ. Cùng với NSLocale, họ cung cấp các phương pháp hiển thị ngày và giờ ở nhiều định dạng và để điều chỉnh thời gian và ngày tháng dựa trên vị trí trên thế giới.

4 Xử lý ngoại lệ

Xử lý ngoại lệ được sử dụng để xử lý các tình huống không mong muốn và nó được cung cấp trong Objective-C với NSException.

5 Xử lý tập tin

Việc xử lý tệp được thực hiện với sự trợ giúp của lớp NSFileManager.

6 Hệ thống tải URL

Một tập hợp các lớp và giao thức cung cấp quyền truy cập vào các giao thức Internet phổ biến.

Liệt kê nhanh là một tính năng của Objective-C giúp liệt kê thông qua một tập hợp. Vì vậy, để biết về cách liệt kê nhanh, trước tiên chúng ta cần biết về tập hợp sẽ được giải thích ở phần sau.

Bộ sưu tập trong Objective-C

Bộ sưu tập là cấu trúc cơ bản. Nó được sử dụng để giữ và quản lý các đối tượng khác. Toàn bộ mục đích của bộ sưu tập là nó cung cấp một cách chung để lưu trữ và truy xuất các đối tượng một cách hiệu quả.

Có một số loại bộ sưu tập khác nhau. Trong khi tất cả chúng đều thực hiện cùng một mục đích là có thể giữ các đối tượng khác, chúng chủ yếu khác nhau ở cách các đối tượng được lấy ra. Các bộ sưu tập phổ biến nhất được sử dụng trong Objective-C là:

  • NSSet
  • NSArray
  • NSDictionary
  • NSMutableSet
  • NSMutableArray
  • NSMutableDictionary

Nếu bạn muốn biết thêm về các cấu trúc này, vui lòng tham khảo lưu trữ dữ liệu trong Foundation Framework .

Cú pháp liệt kê nhanh

for (classType variable in collectionObject ) { 
  statements 
}

Đây là một ví dụ để liệt kê nhanh.

#import <Foundation/Foundation.h>

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   NSArray *array = [[NSArray alloc]
   initWithObjects:@"string1", @"string2",@"string3",nil];
   
   for(NSString *aString in array) {
      NSLog(@"Value: %@",aString);
   }
   
   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-28 06:26:22.835 demo[7426] Value: string1
2013-09-28 06:26:22.836 demo[7426] Value: string2
2013-09-28 06:26:22.836 demo[7426] Value: string3

Như bạn có thể thấy trong đầu ra, mỗi đối tượng trong mảng được in theo thứ tự.

Lùi lại nhanh chóng

for (classType variable in [collectionObject reverseObjectEnumerator] ) { 
  statements 
}

Đây là một ví dụ cho reverseObjectEnumerator trong cách liệt kê nhanh.

#import <Foundation/Foundation.h>

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   NSArray *array = [[NSArray alloc]
   initWithObjects:@"string1", @"string2",@"string3",nil];
   
   for(NSString *aString in [array reverseObjectEnumerator]) {
      NSLog(@"Value: %@",aString);
   }
   
   [pool drain];
   return 0;
}

Bây giờ khi biên dịch và chạy chương trình, chúng ta sẽ nhận được kết quả như sau.

2013-09-28 06:27:51.025 demo[12742] Value: string3
2013-09-28 06:27:51.025 demo[12742] Value: string2
2013-09-28 06:27:51.025 demo[12742] Value: string1

Như bạn có thể thấy trong đầu ra, mỗi đối tượng trong mảng được in nhưng theo thứ tự ngược lại so với kiểu liệt kê nhanh bình thường.

Quản lý bộ nhớ là một trong những quá trình quan trọng nhất trong bất kỳ ngôn ngữ lập trình nào. Đó là quá trình mà bộ nhớ của các đối tượng được cấp phát khi chúng được yêu cầu và phân bổ khi chúng không còn được yêu cầu nữa.

Quản lý bộ nhớ đối tượng là một vấn đề về hiệu suất; nếu một ứng dụng không giải phóng các đối tượng không cần thiết, bộ nhớ của nó sẽ tăng lên và hiệu suất bị ảnh hưởng.

Objective-C Các kỹ thuật quản lý bộ nhớ có thể được phân thành hai loại.

  • "Phát hành giữ lại thủ công" hoặc MRR
  • "Đếm tham chiếu tự động" hoặc ARC

"Phát hành giữ lại thủ công" hoặc MRR

Trong MRR, chúng tôi quản lý bộ nhớ một cách rõ ràng bằng cách tự theo dõi các đối tượng. Điều này được thực hiện bằng cách sử dụng một mô hình, được gọi là đếm tham chiếu, mà NSObject lớp Foundation cung cấp cùng với môi trường thời gian chạy.

Sự khác biệt duy nhất giữa MRR và ARC là việc giữ lại và phát hành được chúng tôi xử lý thủ công trước đây trong khi phần sau được tự động xử lý.

Hình dưới đây là một ví dụ về cách quản lý bộ nhớ hoạt động trong Objective-C.

Vòng đời bộ nhớ của đối tượng Class A được thể hiện trong hình trên. Như bạn có thể thấy, số lưu giữ được hiển thị bên dưới đối tượng, khi số lưu giữ của một đối tượng trở thành 0, đối tượng được giải phóng hoàn toàn và bộ nhớ của nó được phân bổ cho các đối tượng khác sử dụng.

Đối tượng Lớp A được tạo lần đầu tiên bằng phương thức phân bổ / init có sẵn trong NSObject. Bây giờ, số lượng giữ lại trở thành 1.

Bây giờ, lớp B giữ lại Đối tượng của Lớp A và số lượng giữ lại của đối tượng Lớp A trở thành 2.

Sau đó, Lớp C tạo một bản sao của đối tượng. Bây giờ, nó được tạo như một thể hiện khác của Lớp A với các giá trị tương tự cho các biến cá thể. Ở đây, số lưu giữ là 1 và không phải là số lưu giữ của đối tượng ban đầu. Điều này được thể hiện bằng đường chấm trong hình.

Đối tượng được sao chép được phát hành bởi Lớp C bằng cách sử dụng phương thức phát hành và số giữ lại trở thành 0 và do đó đối tượng bị phá hủy.

Trong trường hợp Đối tượng Lớp A ban đầu, số lượng giữ lại là 2 và nó phải được giải phóng hai lần để nó bị phá hủy. Điều này được thực hiện bằng các câu lệnh phát hành của Lớp A và Lớp B, làm giảm số lượng lưu giữ xuống 1 và 0, tương ứng. Cuối cùng, đối tượng bị tiêu diệt.

Quy tắc cơ bản của MRR

  • Chúng tôi sở hữu bất kỳ đối tượng nào chúng tôi tạo: Chúng tôi tạo một đối tượng bằng cách sử dụng phương thức có tên bắt đầu bằng "phân bổ", "mới", "sao chép" hoặc "mutableCopy"

  • Chúng ta có thể nắm quyền sở hữu một đối tượng bằng cách sử dụng giữ lại: Một đối tượng đã nhận thường được đảm bảo vẫn hợp lệ trong phương thức mà nó được nhận và phương thức đó cũng có thể trả lại đối tượng một cách an toàn cho người gọi của nó. Chúng tôi sử dụng giữ lại trong hai trường hợp -

    • Trong việc triển khai phương thức truy cập hoặc phương thức init, để có quyền sở hữu đối tượng mà chúng ta muốn lưu trữ dưới dạng giá trị thuộc tính.

    • Để ngăn một đối tượng bị mất hiệu lực như một tác dụng phụ của một số thao tác khác.

  • Khi chúng ta không còn cần đến nó nữa, chúng ta phải từ bỏ quyền sở hữu đối với một đối tượng mà chúng ta sở hữu: Chúng ta từ bỏ quyền sở hữu đối với một đối tượng bằng cách gửi cho nó một thông báo phát hành hoặc một thông báo autorelease. Theo thuật ngữ Cocoa, việc từ bỏ quyền sở hữu một đối tượng do đó thường được gọi là "giải phóng" một đối tượng.

  • Bạn không được từ bỏ quyền sở hữu đối tượng mà bạn không sở hữu: Đây chỉ là hệ quả của các quy tắc chính sách trước đây được nêu rõ ràng.

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
  [super dealloc];
}

@end

int main() {
   
   /* my first program in Objective-C */
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass sampleMethod];
   
   NSLog(@"Retain Count after initial allocation: %d", 
   [sampleClass retainCount]);
   [sampleClass retain];
   
   NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"SampleClass dealloc will be called before this");
   
   // Should set the object to nil
   sampleClass = nil;
   return 0;
}

Khi chúng ta biên dịch chương trình trên, chúng ta sẽ nhận được kết quả sau.

2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this

"Đếm tham chiếu tự động" hoặc ARC

Trong Đếm Tham chiếu Tự động hoặc ARC, hệ thống sử dụng cùng một hệ thống đếm tham chiếu như MRR, nhưng nó chèn các lệnh gọi phương thức quản lý bộ nhớ thích hợp cho chúng tôi tại thời điểm biên dịch. Chúng tôi rất khuyến khích sử dụng ARC cho các dự án mới. Nếu chúng ta sử dụng ARC, thường không cần hiểu cách triển khai cơ bản được mô tả trong tài liệu này, mặc dù nó có thể hữu ích trong một số trường hợp. Để biết thêm về ARC, hãy xem Chuyển sang Ghi chú phát hành ARC.

Như đã đề cập ở trên, trong ARC, chúng ta không cần thêm các phương thức phát hành và giữ lại vì điều đó sẽ do trình biên dịch xử lý. Trên thực tế, quy trình cơ bản của Objective-C vẫn giống nhau. Nó sử dụng các hoạt động lưu giữ và phát hành nội bộ, giúp nhà phát triển viết mã dễ dàng hơn mà không cần lo lắng về các hoạt động này, điều này sẽ làm giảm cả lượng mã được viết và khả năng rò rỉ bộ nhớ.

Có một nguyên tắc khác được gọi là thu gom rác, được sử dụng trong Mac OS-X cùng với MRR, nhưng kể từ khi nó không được sử dụng trong OS-X Mountain Lion, nó đã không được thảo luận cùng với MRR. Ngoài ra, các đối tượng iOS không bao giờ có tính năng thu gom rác. Và với ARC, OS-X cũng không sử dụng tính năng thu gom rác.

Đây là một ví dụ ARC đơn giản. Lưu ý rằng điều này sẽ không hoạt động trên trình biên dịch trực tuyến vì nó không hỗ trợ ARC.

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
}

@end

int main() {
   /* my first program in Objective-C */
   @autoreleasepool {
      SampleClass *sampleClass = [[SampleClass alloc]init];
      [sampleClass sampleMethod];
      sampleClass = nil;
   }
   return 0;
}

Khi chúng ta biên dịch chương trình trên, chúng ta sẽ nhận được kết quả sau.

2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated