2009-12-15 16 views
7

Tôi không biết tại sao, nhưng nhân dịp tôi đã quản lý để khắc phục một số lỗi biên dịch, đặc biệt làCa cao: Sự khác biệt giữa nhập vào tiêu đề và nhập vào tệp chính là gì?

error expected specifier-qualifier-list before 'someClass' 

nhất bằng cách di chuyển #import "someClass.h" từ file .h vào file .m. Điều này cũng đã làm việc với một vài vấn đề khác tôi đã gặp phải đã được (bí ẩn từ quan điểm của tôi) liên quan đến tiêu đề.

Một số googling cursory đã bật lên câu trả lời "không bao giờ nhập tiêu đề trong tệp tiêu đề" và đó là nơi lời khuyên dừng lại.

Hoặc tôi đã hoàn toàn thực hiện việc này hoặc tôi đã chọn thói quen từ một nơi nào đó, nhưng tôi nghĩ tiêu đề là nơi các tiêu đề được nhập vào. Rõ ràng là không, nhưng bất cứ ai có thể giải thích cho tôi lý do tại sao đó là, và cách ưa thích để nhập tiêu đề là gì?

Trả lời

10

Trừ khi bạn đang kế thừa từ lớp bạn đang đưa vào, bạn không nên bao gồm tiêu đề trong tiêu đề. Nếu bạn cần bao gồm một đối tượng làm biến giao diện, bạn nên sử dụng chỉ thị @class thay thế; điều đó sẽ cho trình biên dịch biết rằng mã định danh đề cập đến một lớp.

Thay vào đó, chỉ nhập tiêu đề trong tệp triển khai. Trình biên dịch sẽ biết rằng các biến cá thể của bạn là con trỏ tới các đối tượng, nhưng nó không biết chi tiết của đối tượng khi phân tích cú pháp tiêu đề. Tất cả những gì cần biết là đó là một lớp học. Trình biên dịch sau đó có thể xem các phương thức của lớp khi phân tích cú pháp tệp triển khai của bạn; tại thời điểm đó, nó cần lớp, để xác minh rằng nó phản hồi các thư bạn đang gửi.


Cập nhật: tôi sẽ cập nhật câu trả lời của tôi để đối phó với một số câu hỏi sau, nhưng Rob Napier has a good follow-up.

+1

Điều gì về 'typedef's và' protocol'? – Joost

+0

bạn sẽ không biết về một hướng dẫn, hoặc một mẫu mã sử dụng điều này? – gargantuan

13

John đưa ra lời khuyên tốt, nhưng đây là một chút nền tảng hơn trên whys, nơi lưu trữ và ngoại lệ.

Có hai mục tiêu để tránh nhập tiêu đề vào tiêu đề: cải thiện thời gian xây dựng gia tăng và tránh phụ thuộc vòng tròn. Nếu bạn nhập vào A.hB.h và nhập B.h vào C.h, sau đó mỗi khi bạn thay đổi bất cứ điều gì trong A.h, bạn phải biên dịch lại C.m, ngay cả khi C.m làm cho không có sử dụng bất kỳ trong những điều quy định tại A.h. Điều này có thể dẫn đến sự lộn xộn thực sự khủng khiếp và không cần thiết, đặc biệt nếu bạn có các tiêu đề thay đổi thường xuyên (như thường thấy trong các giai đoạn phát triển ban đầu).

Mục tiêu đầu tiên là đáng khen ngợi, nhưng đối với các dự án nhỏ, những người quan tâm? Bạn đã có một Quad-core Pro và một bản dựng hoàn chỉnh mất một vài phút, phải không? Nhưng bạn vẫn phải lo lắng về vấn đề thứ hai: phụ thuộc vòng tròn. Tài liệu tham khảo A.h lớp BB.h tham chiếu lớp A. Điều này thực sự có thể xảy ra khá thường xuyên và có thể leo vào một hệ thống khá ngây thơ. Một đối tượng bộ sưu tập có thể tham chiếu kiểu của các đối tượng nó chứa, và các đối tượng có thể tham chiếu kiểu của đối tượng thu thập. Tất cả những gì nó cần là một tham chiếu đơn vì một số phương thức lấy hoặc trả về kiểu đó. Nếu bạn có tiêu đề nhập các tiêu đề khác, khả năng điều này xảy ra nhanh chóng tiếp cận sự thống nhất. Bạn kết thúc với nhập khẩu đệ quy, và các lỗi biên dịch thời gian có thể là tâm-thổi. "Tôi biết rằng typdef được xác định!Nó ở ngay đó! Nó đã được nhập! "Nhưng, nó chưa được phân tích cú pháp khi bạn nhập tiêu đề này. Đây là nguyên nhân gây ra lỗi của bạn ở trên. bạn nên), tránh nhập tiêu đề vào các tiêu đề ... trừ ....

một số tiêu đề bạn nhập khẩu. lớp cha của bạn dĩ nhiên rồi. các tập tin định nghĩa một @protocol bạn thực hiện hoặc typedef bạn sử dụng. Vì vậy, yeah, bạn phải bao gồm những người đó.

Và điều gì về tiêu đề hệ thống? Vâng, họ sẽ không bao giờ ause churn, và rõ ràng là họ sẽ không gây ra nhập khẩu đệ quy, vì vậy họ đang tốt. Tôi không khuyến khích mọi người sử dụng các khai báo chuyển tiếp @class cho những thứ trong tiêu đề hệ thống. Nó tạo thêm công việc cho người dùng tiêu đề của bạn không có giá trị. Để vệ sinh tiêu đề tốt, hãy nhớ đính kèm tiêu đề hệ thống trong các dấu ngoặc vuông < > và tiêu đề của bạn trong "dấu ngoặc kép".

Vì vậy, nó không phải là một câu hỏi tầm thường, nhưng quy tắc đơn giản là: tránh nhập tiêu đề người dùng vào các tiêu đề người dùng khác bất kỳ lúc nào trình biên dịch sẽ cho phép bạn.

+0

cảm ơn bạn rất nhiều vì điều đó. – gargantuan

0

Bạn sẽ không chỉ bao gồm tiêu đề của mình vào tệp triển khai mà còn bao gồm các tệp khác bằng cách sử dụng lớp đó. Nếu bạn bao gồm tất cả các phụ thuộc trong tiêu đề, tất cả các tệp khác bao gồm tiêu đề đó chỉ để sử dụng lớp cụ thể mà nó định nghĩa sẽ tự bao gồm tất cả các phụ thuộc.

Điều này không chỉ gây ồn mà còn dẫn đến các sự cố khi bạn có các lớp tham chiếu. Mỗi lớp sẽ phải được nhập trước một lớp khác, dẫn đến một lớp được nhập trước và sau đó không thể tìm thấy loại của lớp khác. Điều này dẫn đến thông báo lỗi khó hiểu mà bạn đã đăng, điều này có nghĩa là trình biên dịch không thể tìm thấy loại someClass.

Bằng cách di chuyển hàng nhập vào tệp triển khai của bạn và chuyển tiếp các lớp và loại trong tiêu đề của bạn (sử dụng @class, @protocol, v.v.), bạn có thể tránh những vấn đề này.

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