2011-07-20 39 views
5

Sau đây là một đoạn trích từ thực hiện một Xem lý lịch thành Bộ điều khiển:Hiểu Objective-C phạm vi vấn đề

- (void)myOtherAwesomeMethod 
{ 
    [self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector 
} 

- (void)myAwesomeMethod 
{ 
    NSLog(@"%@", @"Calling my awesome method..."); 
} 

- (void)viewDidLoad 
{ 
    [self myAwesomeMethod]; 

    [self myOtherAwesomeMethod]; 
} 

Tôi không có myAwesomeMethod phương pháp khai báo trong tập tin tiêu đề của tôi, nhưng tại sao nó mà tôi có thể gọi myAwesomeMethod trong viewDidLoad, nhưng không phải trong số myOtherAwesomeMethod?

Tôi biết giải pháp cho lỗi này là khai báo phương thức trong tệp tiêu đề của tôi, nhưng tôi muốn hiểu tại sao điều này xảy ra.

+0

bạn đang gọi '-myOtherAwesomeMethod' ở đâu? – vikingosegundo

+1

Tôi tin rằng đó chỉ là cảnh báo, không phải lỗi? – tia

+0

Ngoài ra bạn chỉ có thể NSLog chuỗi, không cần phải định dạng nó. –

Trả lời

11

Trong C, quy tắc là: bạn phải khai báo trước khi sử dụng.

Tệp được biên soạn từ trên xuống dưới. Vì vậy, đây là những gì đang xảy ra trong mã của bạn:

  1. Trình biên dịch đọc khai báo @interface cho lớp của bạn. Vì bạn nói không phương thức nào được khai báo trong tệp tiêu đề, không có trong bảng biểu tượng.

    bảng biểu tượng của bạn có chứa: không có gì chưa

  2. Trình biên dịch lần đọc định nghĩa phương pháp cho myAwesomeMethod. Bạn chưa khai báo nó, vì vậy nó được thêm vào bảng biểu tượng. Phần thân của phương thức chứa một cuộc gọi đến NSLog, được khai báo từ lâu trong một tiêu đề do Apple cung cấp cho bạn.

    bảng biểu tượng của bạn có chứa: myAwesomeMethod

  3. Trình biên dịch lần đọc định nghĩa phương pháp cho viewDidLoad; nó đã thực sự được khai báo trong tệp tiêu đề của một siêu lớp. Phần thân của phương thức chứa một cuộc gọi đến myAwesomeMethod, đã được tìm thấy! Nó cũng có một cuộc gọi đến myOtherAwesomeMethod. Chưa bao giờ nghe về nó!

    Bây giờ, đây không phải là lỗi, vì nó vẫn có thể tạo mã để thực hiện cuộc gọi. Nó có thể suy ra các kiểu đối số bằng cách bạn sử dụng nó như thế nào (trong trường hợp này, không có đối số). Nó không thể chắc chắn về kiểu trả về, mặc dù (chỉ vì bạn không sử dụng giá trị trả về không có nghĩa là không có). Vì vậy, nó tiến hành trên giả định rằng cuộc gọi trả về id và tạo ra một cảnh báo.

    bảng biểu tượng của bạn có chứa: myAwesomeMethod

  4. Cuối cùng, trình biên dịch lần đọc định nghĩa phương pháp cho myOtherAwesomeMethod. Nó được thêm vào bảng biểu tượng. Nó biên dịch cơ thể, trong đó có một cuộc gọi đến myAwesomeMethod, có trong bảng. Tất cả là cũng kết thúc tốt.

    Vào cuối của tập tin, bảng biểu tượng của bạn có chứa: myAwesomeMethod, myOtherAwesomeMethod

Nếu bạn đang đến từ một ngôn ngữ như Java, điều này có vẻ ngớ ngẩn, nhưng đó là bởi vì Java hoạt động khác với C Trong Java, mã nguồn được biên dịch và liên kết trong một bước; bạn không thể biên dịch một lớp tham chiếu đến một lớp khác mà không có sẵn mã nguồn hoặc các tệp lớp. Điều đó có thể là một rắc rối, nhưng mặt khác, bạn không bao giờ cần phải khai báo ngoài các định nghĩa.

Trong C, việc biên dịch và liên kết là các bước khác nhau.Trình biên dịch chỉ tạo mã đối tượng đề cập đến các ký hiệu có thể được định nghĩa ở nơi khác; nó sử dụng các khai báo để đảm bảo nó tạo mã đúng. Trình liên kết có trách nhiệm kết hợp tất cả các ký hiệu đó với các định nghĩa trong các thư viện khác, tĩnh hoặc động.

Trong mục tiêu-C, trình liên kết không thực sự biết/quan tâm đến các thư mục tiêu C, vì không có cách nào để biết thời gian biên dịch/liên kết cho dù đối tượng có thể trả lời thư. Vì vậy, nó vượt qua buck để thời gian chạy, mà ném một ngoại lệ nếu bạn nhận được rằng đến nay mà không có một định nghĩa phương pháp.

+0

Cảm ơn @ benzado, tôi phát hiện ra rằng thứ tự là thủ phạm. Tôi không thực sự cần khai báo nó ở đâu cả, nhưng định nghĩa phương thức cần phải đến trước khi nó được gọi. Tôi vẫn chấp nhận câu trả lời của bạn cho lời giải thích tuyệt vời. – pixelfreak

0

Tôi thừa nhận tôi không chắc chắn lý do tại sao nó hoạt động trong viewDidLoad.

Lưu ý rằng lỗi nói "không DECLARE" một phương thức. Đó là một gợi ý rằng nó đang tìm kiếm một khai báo (thường là trong một tiêu đề) .. tức là một nguyên mẫu hàm.

Tuy nhiên, không có gì cho biết tuyên bố phải nằm trong tiêu đề. YOu có thể đặt nó ở đầu tệp triển khai nếu bạn không gọi phương thức đó từ bên ngoài tệp.

Các vấn đề liên quan