สร้างอินสแตนซ์คลาส Object-c ตามชื่อ?


95

เป็นไปได้ไหมที่จะสร้างอินสแตนซ์ของคลาสตามชื่อ สิ่งที่ต้องการ:

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

ฉันไม่รู้ว่ามันเป็นไปได้หรือไม่ใน objective-c แต่ดูเหมือนว่าจะเป็น

คำตอบ:



39

NSClassFromString()เสี่ยงต่อการพิมพ์ชื่อคลาสผิดหรือใช้คลาสที่ไม่มีอยู่ คุณจะไม่พบจนกว่ารันไทม์หากคุณทำผิดพลาด แต่ถ้าคุณใช้ชนิด Object-c ในตัวClassเพื่อสร้างตัวแปรคอมไพลเลอร์จะตรวจสอบว่าคลาสนั้นมีอยู่จริง

ตัวอย่างเช่นใน.h:

@property Class NameOfClass;

จากนั้นใน.m:

id object = [[NameOfClass alloc] init];

หากคุณพิมพ์ชื่อคลาสผิดหรือหากไม่มีอยู่คุณจะได้รับข้อผิดพลาดในขณะคอมไพล์ ฉันคิดว่านี่เป็นรหัสที่สะอาดกว่า


เอาเลยเพื่อน ไม่แน่ใจว่าเป็นคำตอบที่ดีที่สุดเนื่องจากต้องใช้สองบรรทัดและมีไดนามิกน้อยกว่า แต่ก็เพิ่มคะแนนเหมือนกันทั้งหมด
Chris McCall

1
ฉันคิดว่าคุณอาจพูดได้ว่ามันมีไดนามิกน้อยกว่าเพราะฉันใช้สัญลักษณ์แทนสตริง อย่างไรก็ตามหากคุณรู้จักคลาสที่คุณต้องการเมื่อคุณเขียนโค้ดคุณควรใช้สัญลักษณ์เพื่อหลีกเลี่ยงการพิมพ์ผิดที่อาจเกิดขึ้นได้
Simon Woodside

@sbwoodside: งานนี้ได้ยังไง? ฉันลองแล้วและได้รับ "สัญลักษณ์ที่ไม่ได้กำหนดสำหรับสถาปัตยกรรม" จากตัวเชื่อมโยง
Lars Schneider

เปลี่ยนเป็น [[[คลาสตนเอง] จัดสรร] init]; คุณไม่ต้องการสิ่งอื่นใด
Nick Turner

กรณีการใช้งานของ OP นั้นเป็นมากกว่า Legit - เป็นฐานสำหรับการทำให้ลำดับชั้นของวัตถุเป็นลำดับชั้นไปยังไฟล์ / memory-block / plist / อะไรก็ตาม หลายครั้งที่คุณไม่ทราบล่วงหน้าว่าจะต้องสร้างอินสแตนซ์ชั้นเรียนใด กรณีการใช้งานของฉันคือต้อง "ลงทะเบียน" gazillion "NSValueTransformer" ที่น่าเบื่อและแทนที่จะทำซ้ำ 40 ครั้ง - ฉันแค่สแกน NSArray ของชื่อหม้อแปลง - และสร้าง / ลงทะเบียนจากสตริง
Motti Shneor

8

หากคุณกำลังทำงานกับ Objective-C โดยไม่ต้องNeXTstep( OS X, iOS, GNUstepระบบ ฯลฯ ) หรือคุณเพียงแค่คิดว่าวิธีนี้คือการทำความสะอาดแล้วคุณสามารถใช้ประโยชน์จากObjective-C ภาษา runtime library ของ API ภายใต้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 ];

ภายใต้ Objective-C (1.0 หรือเวอร์ชันที่ไม่มีชื่อ) คุณจะใช้สิ่งต่อไปนี้:

#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 ];

ฉันยังไม่ได้ทดสอบ1.0เวอร์ชัน แต่ฉันได้ใช้2.0ฟังก์ชันในโค้ดที่อยู่ในระหว่างการผลิต โดยส่วนตัวแล้วฉันเชื่อว่าการใช้2.0ฟังก์ชันนี้จะสะอาดกว่าถ้ามีมากกว่าฟังก์ชัน NS เนื่องจากใช้พื้นที่น้อยกว่า: the length of the name in bytes + 1 ( null terminator )สำหรับ 2.0 API เทียบกับthe sum of two pointers (isa, cstring)a size_t length (cstring_length)และlength of the string in bytes + 1สำหรับNeXTSTEPAPI


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

@implementation Magic

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

@end

จากนั้นจะใช้มัน:

Car *car = [Magic createInstanceOfClass:[Car class]];
[car engineTurnOn];
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.