Sử dụng C ++ với Cocoa thay vì Objective-C?


122

Tôi muốn viết các ứng dụng sử dụng C ++ và các khuôn khổ Cocoa vì Apple không sản xuất Carbon 64-bit. C ++ có vẻ khá đơn giản trong việc triển khai nó trên Linux và Windows nhưng trên Mac OS X, có vẻ như cần phải có thêm các đoạn mã cụ thể của Apple (như trình bao bọc Obj-C). Có vẻ như Apple đang buộc các nhà phát triển viết bằng Objective-C thay vì C ++, mặc dù tôi có thể sai.

Tôi đang cố gắng tìm một con đường để viết mã trên Mac có thể dễ dàng giữ được nhiều nền tảng. Phải viết mã bằng C ++ cho Linux / Windows và sau đó viết lại các phần lớn trong Objective-C sẽ rất kém hiệu quả.

Có cách nào để viết mã bằng C ++ sẽ được hỗ trợ trong tương lai và được hỗ trợ trong Xcode không? Ngoài ra, nếu điều này là có thể, tôi sẽ kết hợp C ++ và Objective-C trong Xcode như thế nào? Cảm ơn.

Câu trả lời:


110

Bạn không thể viết một ứng dụng Cocoa hoàn toàn bằng C ++. Cacao chủ yếu dựa vào khả năng ràng buộc muộn của Objective-C đối với nhiều công nghệ cốt lõi của nó như Liên kết giá trị chính, các đại biểu (kiểu Cacao) và mô hình hành động mục tiêu. Các yêu cầu liên kết muộn khiến việc triển khai Cocoa API rất khó khăn trong một ngôn ngữ được đánh máy, giới hạn thời gian biên dịch như C ++ ⁱ. Tất nhiên, bạn có thể viết một ứng dụng C ++ thuần chạy trên OS X. Nó chỉ không thể sử dụng các API Cocoa.

Vì vậy, bạn có hai tùy chọn nếu bạn muốn chia sẻ mã giữa các ứng dụng C ++ trên các nền tảng khác và ứng dụng dựa trên Cocoa của bạn. Đầu tiên là viết lớp mô hình trong C ++ và GUI trong Cocoa. Đây là cách tiếp cận phổ biến được sử dụng bởi một số ứng dụng rất lớn, bao gồm cả Mathematica . Mã C ++ của bạn có thể được giữ nguyên (bạn không cần phần mở rộng táo "sôi nổi" để viết hoặc biên dịch C ++ trên OS X). Lớp điều khiển của bạn có thể sẽ sử dụng Objective-C ++ (có lẽ là tiện ích mở rộng Apple "sôi nổi" mà bạn đề cập đến). Objective-C ++ là một tập hợp con của C ++, cũng như Objective-C là tập hợp con của C. Trong Objective-C ++, bạn có thể thực hiện thông báo kiểu objc chuyển các cuộc gọi (như [some-objc-object callMethod];) từ bên trong một hàm C ++. Ngược lại, bạn có thể gọi các hàm C ++ từ trong mã ObjC như:

@interface MyClass {
    MyCPPClass *cppInstance;
}
@end

@implementation MyClass
- (id)init {
    if(self = [super init]) {
        cppInstance = new MyCPPClass();
    }
    return self;
}
- (void) dealloc {
    if(cppInstance != NULL) delete cppInstance;
    [super dealloc];
}
- (void)callCpp {
    cppInstance->SomeMethod();
}
@end

Bạn có thể tìm hiểu thêm về Objective-C ++ trong hướng dẫn ngôn ngữ Objective-C . Lớp xem sau đó có thể là Objective-C thuần túy.

Tùy chọn thứ hai là sử dụng bộ công cụ C ++ đa nền tảng. các Qtbộ công cụ có thể phù hợp với hóa đơn. Các bộ công cụ đa nền tảng thường bị người dùng Mac coi thường vì chúng không có được tất cả các chi tiết về giao diện và cảm nhận một cách chính xác và người dùng Mac mong đợi sự cải tiến trong giao diện người dùng của các ứng dụng Mac. Tuy nhiên, Qt thực hiện một công việc tốt đáng ngạc nhiên và tùy thuộc vào đối tượng và việc sử dụng ứng dụng của bạn, nó có thể đủ tốt. Ngoài ra, bạn sẽ mất đi một số công nghệ dành riêng cho OS X như Core Animation và một số chức năng QuickTime, mặc dù có những thay thế gần đúng trong Qt API. Như bạn đã chỉ ra, Carbon sẽ không được chuyển sang 64-bit. Vì Qt được triển khai trên các API Carbon, Trolltech / Nokia đã phải chuyển Qt sang API Cocoa để làm cho nó tương thích với 64-bit. Tôi hiểu rằng bản phát hành tiếp theo của Qt (hiện đang được phát hành) hoàn thành quá trình chuyển đổi này và tương thích 64-bit trên OS X. Bạn có thể muốn xem nguồn của Qt 4.5 nếu bạn quan tâm đến việc tích hợp C ++ và các API Cocoa.


ⁱ Trong một thời gian, Apple đã cung cấp Cocoa API cho Java, nhưng cầu nối này yêu cầu điều chỉnh bằng tay rộng rãi và không thể xử lý các công nghệ tiên tiến hơn như Key-Value Bindings được mô tả ở trên. Hiện tại, các ngôn ngữ có ràng buộc thời gian chạy, được nhập động như Python, Ruby, v.v. là lựa chọn thực sự duy nhất để viết ứng dụng Cocoa mà không có Objective-C (mặc dù tất nhiên các cầu nối này sử dụng Objective-C).


Tôi hiện đang cố chuyển ứng dụng Ogre3D nhỏ của mình, có vẻ RẤT đau. Apple đang cố gắng chuyển đổi mọi người sang Objc hay đây thực sự là một tính năng?
jokoon

68

Chà, nghe có vẻ ngớ ngẩn, nhưng thực ra chúng ta có thể viết mã C ++ thuần túy để tạo GUI cho Mac OS X, nhưng chúng ta phải liên kết với Cocoa framework.

/*
 * test1.cpp
 * This program shows how to access Cocoa GUI from pure C/C++
 * and build a truly functional GUI application (although very simple).
 * 
 * Compile using:
 *   g++ -framework Cocoa -o test1 test1.cpp
 *
 * that will output 'test1' binary.
 */


#include <CoreFoundation/CoreFoundation.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <iostream>

extern "C" int NSRunAlertPanel(CFStringRef strTitle, CFStringRef strMsg,
                               CFStringRef strButton1, CFStringRef strButton2, 
                               CFStringRef strButton3, ...);


int main(int argc, char** argv)
{
    id app = NULL;
    id pool = (id)objc_getClass("NSAutoreleasePool");
    if (!pool)
    {
        std::cerr << "Unable to get NSAutoreleasePool!\nAborting\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("alloc"));
    if (!pool)
    {
        std::cerr << "Unable to create NSAutoreleasePool...\nAborting...\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("init"));

    app = objc_msgSend((id)objc_getClass("NSApplication"),
                       sel_registerName("sharedApplication"));

    NSRunAlertPanel(CFSTR("Testing"),
                    CFSTR("This is a simple test to display NSAlertPanel."),
                    CFSTR("OK"), NULL, NULL);

    objc_msgSend(pool, sel_registerName("release"));
    return 0;
}

17
Đây là điều tuyệt vời. Có những ví dụ phức tạp hơn có sẵn không? Ví dụ, mở một NSWindow?
imallett,

test1.cpp: Trong hàm 'int main (int, char **)': test1.cpp: 26: 48: error: không thể chuyển đổi 'Class {aka objc_class *}' thành 'id {aka objc_object *}' trong id khởi tạo pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: error: không thể chuyển đổi 'Class {aka objc_class *}' thành 'id {aka objc_object *}' cho đối số '1' thành 'objc_object * objc_msgSend (id, SEL, ...)' sel_registerName ("sharedApplication")); ^
Jichao

6
@Jichao thấy khả năng tương thích Clang với loại Objective-C nội - sửa chữa rất đơn giản: thay thế objc_getClassvới(id)objc_getClass
Dmitry Isaev

Làm thế nào tôi có thể sử dụng một chuỗi std :: để đặt ví dụ. tiêu đề cho bảng cảnh báo? Tôi đã cố gắng sử dụng c_str () và giống nhau nhưng không làm việc ...
mdre

1
Điều này không biên dịch nữa trong macOS Catalina
JC Rocamonde

18

Có, bạn chỉ có thể sử dụng C ++ (tức là viết nó trong các tệp * .cpp) và thậm chí trộn C ++ và Objective-C bên trong các tệp * .mm (mã Objective-C tiêu chuẩn được lưu trữ trong các tệp * .m).

Tất nhiên, bạn vẫn phải sử dụng Objective-C cho giao diện người dùng của mình và tạo các trình bao bọc Objective-C cho các đối tượng C ++ của bạn. Một tùy chọn khác là chuyển sang Qt , một C ++ Framework hỗ trợ Windows, Mac OS X và Linux - và sẽ được phát hành theo LGPL với phiên bản 4.5 tiếp theo.


23
Lưu ý rằng nếu bạn sử dụng Qt, ứng dụng của bạn sẽ rất tệ. Các ứng dụng dựa trên Qt trông không giống các ứng dụng Mac gốc. (Ví dụ: hãy xem Google Earth.)
Peter Hosey

15
Peter: Điều đó không đúng chút nào. Các ứng dụng dựa trên Qt có thể trông giống hệt với các ứng dụng Mac gốc, bạn chỉ cần thực hiện điều chỉnh trên từng nền tảng, điều này dễ dàng hơn nhiều so với việc viết GUI gốc trên mỗi nền tảng.
Mike McQuaid

12
Mike, bạn đã thông tin sai. Trong số những thiếu sót khác của chúng, các ứng dụng dựa trên Qt trên mac hoàn toàn không sử dụng các điều khiển gốc và thư viện Qt tự thực hiện tất cả các bản vẽ. Điều này có nghĩa là các ứng dụng Qt không nhận được bất kỳ khả năng tăng tốc phần cứng nào cho kết xuất 2D, chúng không đồng bộ với các thay đổi giao diện người dùng mà Apple thực hiện đối với các điều khiển tiêu chuẩn và ứng dụng Qt không thể cung cấp khả năng tuân thủ ADA hoặc tập lệnh trừ khi bạn phát minh lại bánh xe mình. Nói cách khác, KHÔNG NHẬN gửi ứng dụng Qt trên Mac. Google có thể thoát khỏi nó: bạn không thể.
NSResponder

13
Họ sử dụng các điều khiển gốc, đó là lý do tại sao Qt có phiên bản Cacao và Carbon. Nó có các vấn đề khác nhưng nhiều người gửi các ứng dụng Qt trên Mac và chúng hoạt động tốt (và hoàn hảo với một chút tinh chỉnh).
Mike McQuaid

2
Chỉ cần sử dụng kiểm soát nguồn gốc không có nghĩa là nó sẽ xem xét và cảm thấy như các ứng dụng bản địa. Điều tạo nên cảm giác bản địa là sự khác biệt của từng hệ điều hành. Nếu bạn điều chỉnh ứng dụng của mình để được cảm nhận trên một nền tảng cụ thể, thì ứng dụng đó sẽ không giống với nền tảng khác. Và, việc tinh chỉnh các hành vi nhỏ trên một lớp trừu tượng luôn khó hơn thực hiện trên lớp nguyên bản.
eonil 12/12/12

9

Có, bạn có thể trộn chúng.

Bạn cần sử dụng Objective-C để trực tiếp thao tác trên các đối tượng GUI của mình và nhận thông báo từ chúng.

Các đối tượng Objective-C này có thể gọi trực tiếp logic C ++ nếu bạn đặt chúng trong tệp .mm, thay vì tệp .m Objective-C thuần túy. Lưu ý rằng bạn có thể thấy (nhiều) lời khuyên cũ hơn đề xuất sử dụng chữ hoa .M để biểu thị Objective-C ++ nhưng điều này rất dễ hiểu và có thể gây nhầm lẫn cho bạn cũng như trình biên dịch.

Bạn không cần phải bọc từng đối tượng C ++ nhưng mã Objective-C của bạn sẽ cần chứa các con trỏ tới chúng.

Apple không còn công bố bất kỳ mẫu nào cho thấy cách thực hiện điều này.

Có một video tuyệt vời của Peter Steinberger được lưu trữ tại Realm [Objective] C ++: Điều gì có thể xảy ra sai? Tôi thực sự khuyên mọi người vẫn đang sử dụng Objective-C ++ và bạn có thể đọc lướt nhanh bản ghi.


@SteveS liên kết của bạn cũng bị hỏng
fferri

@fferi - Liên kết Steinberger ở trên đã được sửa. Tích hợp Cacao Cacbon có từ năm 2007 từ developer.apple.com, Apple đã gỡ bỏ nó. Điều này chỉ ra rằng bạn THỰC SỰ không nên viết mã mới bằng API Carbon. Tại thời điểm này, ngay cả việc duy trì mã hiện có bằng Carbon cũng rất rủi ro. Tham khảo các câu trả lời được chấp nhận cho câu hỏi này, hoặc cái này nếu bạn cần để trộn C ++ / Objective C, nhưng bạn không nên sử dụng Carbon. Điều đó nói rằng, ở đây: Carbon-Cocoa-Integration
SteveS

4

Nếu bạn chỉ muốn sử dụng vani C ++ đơn giản, điều này hoàn toàn được hỗ trợ và thực sự không khác biệt so với bất kỳ nền tảng nào khác. Xcode thậm chí còn có một mẫu cho nó trong Tệp> Dự án mới> Tiện ích dòng lệnh> Công cụ C ++. Ngoài ra, một số thư viện nguồn mở phổ biến (libcurl, libxml2, sqlite, v.v.) đi kèm với OS X và có sẵn để liên kết động. Bạn không cần phải sử dụng Cocoa hoặc bất cứ thứ gì dành riêng cho Apple nếu bạn không muốn.

Nếu bạn muốn sử dụng Cacao trong một số phần nhất định của ứng dụng, hãy xem Objective-C ++ . Bạn có thể trộn C ++ và Objective-C trong cùng một tệp bằng cách đặt cho nó phần mở rộng là .mm, hoặc bằng cách nhấp chuột phải vào tệp trong Xcode và chọn Get Info> General, sau đó thay đổi Loại tệp thành sourcecode.cpp.objcpp. Tùy chọn thứ hai hữu ích nếu bạn có tệp .cpp mà bạn muốn sử dụng Objective-C trong #ifdef dành riêng cho Mac.


1
BTW, mẫu C ++ (thực sự hữu ích) đã biến mất với các phiên bản gần đây của Xcode (4.x và 5.x)
Jay

1

Mặc dù đây là câu hỏi cũ ...

Tôi đã cố gắng tạo trình bao bọc C ++ của một số lớp Cacao .

Đó là kinh nghiệm khá tốt đẹp. C ++ cung cấp độ an toàn kiểu tốt hơn Objective-C và khiến tôi viết ít mã hơn. Nhưng thời gian biên dịch và độ an toàn của bộ nhớ kém hơn. Có thể nhưng một số tính năng dựa trên động không dễ xử lý. Tôi nghĩ không có ý nghĩa gì khi xử lý nó trên C ++.

Dù sao dự án của tôi cuối cùng đã bị bỏ dở do thông báo về Swift. Nó đã xóa tất cả những lý do tôi muốn sử dụng C ++ lúc đầu và cung cấp nhiều hơn và tốt hơn.


0

Nếu bạn đang viết một ứng dụng đồ họa thuần túy, tức là bạn đang vẽ mọi thứ bằng cách sử dụng mã, hãy xem xét openFrameworks . Đó là một ngôn ngữ lập trình đồ họa mã nguồn mở được xây dựng trên C / C ++. Nó có các addon cho phép mọi người mở rộng ngôn ngữ. Họ có một addon cho iphone . Tôi tin rằng nó đi kèm với thư viện và các dự án XCode sẽ giúp bạn biên dịch các ứng dụng cho iPhone và iPod touch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.