Tạo cá thể lớp mục tiêu-c theo tên?


95

Có thể tạo một thể hiện của một lớp theo tên không? Cái gì đó như:

NSString* className = @"Car";
id* p = [Magic createClassByName:className];
[p turnOnEngine];

Tôi không biết liệu điều này có thể xảy ra trong mục tiêu-c hay không nhưng có vẻ như nó sẽ xảy ra,

Câu trả lời:



38

NSClassFromString()có nguy cơ gõ nhầm tên lớp hoặc sử dụng một lớp không tồn tại. Bạn sẽ không phát hiện ra cho đến thời gian chạy nếu bạn mắc lỗi đó. Thay vào đó, nếu bạn sử dụng kiểu target-c có sẵn của Classđể tạo một biến, thì trình biên dịch sẽ xác minh rằng lớp đó tồn tại.

Ví dụ, trong .h:

@property Class NameOfClass;

và sau đó trong .m:

id object = [[NameOfClass alloc] init];

Nếu bạn nhập sai tên lớp hoặc nếu nó không tồn tại, bạn sẽ gặp lỗi tại thời điểm biên dịch. Ngoài ra tôi nghĩ rằng đây là mã sạch hơn.


Đây rồi, anh bạn. Không hoàn toàn chắc chắn đó là câu trả lời tốt nhất, vì nó yêu cầu hai dòng và kém năng động hơn, nhưng tất cả đều được ủng hộ
Chris McCall

Tôi cho rằng bạn có thể nói rằng nó kém năng động hơn vì tôi đã sử dụng một biểu tượng thay vì một chuỗi. Tuy nhiên, nếu bạn biết lớp mà bạn muốn khi viết mã, thì bạn nên sử dụng ký hiệu để tránh lỗi chính tả có thể xảy ra.
Simon Woodside

@sbwoodside: Làm thế nào điều này có thể hoạt động? Tôi đã thử nó và tôi nhận được "Các ký hiệu không xác định cho kiến ​​trúc" từ trình liên kết.
Lars Schneider

Thay đổi nó thành [[[self class] cert] init]; Bạn không cần bất cứ thứ gì khác.
Nick Turner

Trường hợp sử dụng của OP còn hơn cả tính hợp pháp - nó là cơ sở cho bất kỳ tuần tự hóa phân cấp đối tượng nào thành tệp / bộ nhớ-khối / plist / bất kỳ thứ gì. Nhiều khi bạn KHÔNG BIẾT trước lớp nào bạn sẽ cần phải bắt đầu. Trường hợp sử dụng của tôi là nhu cầu tẻ nhạt để "đăng ký" gazillion "NSValueTransformer" và thay vì sao chép [NSValueTransformer setValueTransformer: MyTransformerAblank] init] forName: @ "MyTransformerA"]; 40 lần - tôi chỉ quét NSArray tên máy biến áp - và tạo / đăng ký chúng từ chuỗi.
Motti Shneor

8

Nếu bạn đang làm việc với Objective-C mà không có NeXTstep( OS X, iOS, GNUstephệ thống vv) hoặc bạn chỉ nghĩ rằng phương pháp này là sạch, sau đó bạn có thể sử dụng các API runtime thư viện của ngôn ngữ Objective-C . Dưới Objective-C 2.0:

#import <objc/runtime.h>
//Declaration in the above named file
id objc_getClass(const char* name);
//Usage
id c = objc_getClass("Object");
[ [ c alloc ] free ];

Trong Objective-C (phiên bản 1.0 hoặc chưa được đặt tên), bạn sẽ sử dụng những điều sau:

#import <objc/objc-api.h>
//Declaration within the above named file
Class objc_get_class( const char* name);
//Usage
Class cls = objc_get_class( "Test" );
id obj = class_create_instance( cls );
[ obj free ];

Tôi chưa thử nghiệm 1.0phiên bản, tuy nhiên tôi đã sử dụng 2.0hàm trong mã hiện đang được sản xuất. Cá nhân tôi tin rằng việc sử dụng 2.0hàm này sẽ sạch hơn nếu có sẵn so với hàm NS vì nó tốn ít dung lượng hơn: the length of the name in bytes + 1 ( null terminator )đối với API 2.0 so với the sum of two pointers (isa, cstring), a size_t length (cstring_length)length of the string in bytes + 1đối với NeXTSTEPAPI.


2
@interface Magic : NSObject
+ (id)createInstanceOfClass:(Class)classe;
@end

@implementation Magic

+ (id)createInstanceOfClass:(Class)classe
{
    return [[classe alloc] init];
}

@end

Sau đó, để sử dụng nó:

Car *car = [Magic createInstanceOfClass:[Car class]];
[car engineTurnOn];
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.