ฉันจะสร้างตัวเลือกแบบไดนามิกในรันไทม์ด้วย Objective-C ได้อย่างไร


93

ฉันรู้วิธีสร้างSELเวลาคอมไพล์โดยใช้@selector(MyMethodName:)แต่สิ่งที่ฉันต้องการทำคือสร้างตัวเลือกแบบไดนามิกจากNSStringไฟล์. เป็นไปได้หรือไม่?

สิ่งที่ฉันทำได้:

SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];

สิ่งที่ฉันต้องการทำ: (รหัสหลอกเห็นได้ชัดว่าสิ่งนี้ใช้ไม่ได้)

SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];

ฉันค้นหาเอกสาร Apple API แล้ว แต่ไม่พบวิธีที่ไม่ต้องอาศัย@selector(myTarget:)ไวยากรณ์เวลาคอมไพล์

คำตอบ:


180

ฉันไม่ใช่โปรแกรมเมอร์ Objective-C เป็นเพียงโซเซียลมีเดียแต่NSSelectorFromStringอาจเป็นสิ่งที่คุณต้องการ มีการกล่าวถึงความชัดเจนในRuntime Referenceซึ่งคุณสามารถใช้เพื่อแปลงสตริงเป็นตัวเลือก


5
ฉันต้องการแปรง Google-fu นั่นคือสิ่งที่ฉันกำลังมองหา (หรือไม่เป็นอย่างนั้น)
Craigb

ฉันยังคงมีลิงก์ที่บินไปมาในบุ๊กมาร์กของฉันเนื่องจากฉันได้อ่านเอกสาร Objective-C 2.0 เมื่อสองสามวันก่อน
Torsten Marek

40

ตามเอกสาร XCode โดยพื้นฐานแล้วรหัส psuedocode ของคุณจะทำให้ถูกต้อง

การกำหนดค่าให้กับตัวแปร SEL ในเวลาคอมไพล์มีประสิทธิภาพมากที่สุดด้วยคำสั่ง @selector () อย่างไรก็ตามในบางกรณีโปรแกรมอาจต้องแปลงสตริงอักขระเป็นตัวเลือกที่รันไทม์ สามารถทำได้ด้วยฟังก์ชัน NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

แก้ไข: แย่มากช้าเกินไป : ป


2
NSStringFromSelector(@"doWork")แปลงเป็นอีกทางหนึ่ง (แค่ fyi)
bendytree

8
ฉันคิดว่าคุณหมายถึง NSStringFromSelector (@selector (doWork))
jpswain

แล้วตัวเลือกนั้นควรจะทำอย่างไร? เราไม่ควรระบุบล็อคหรืออะไร?
user4951

13

ฉันต้องบอกว่ามันซับซ้อนกว่าที่คำตอบของผู้ตอบก่อนหน้านี้เล็กน้อยอาจแนะนำ ... หากคุณต้องการสร้างตัวเลือกจริงๆ ... ไม่ใช่แค่ "เรียกหนึ่ง" ที่คุณ "วางไว้" .. .

คุณต้องสร้างตัวชี้ฟังก์ชันที่จะเรียกโดยเมธอด "ใหม่" ของคุณ .. ดังนั้นสำหรับวิธีการที่[self theMethod:(id)methodArg];คุณต้องการเขียน ...

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};

จากนั้นคุณต้องสร้างIMPบล็อกแบบไดนามิกคราวนี้ส่งผ่าน "ตัวเอง" SELและข้อโต้แย้งใด ๆ ...

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);

และเพิ่มลงในชั้นเรียนของคุณพร้อมกับลายเซ็นวิธีการที่ถูกต้องสำหรับตัวดูดทั้งหมด (ในกรณีนี้การ"v@:@"คืนค่าเป็นโมฆะผู้เรียกวัตถุอาร์กิวเมนต์ของวัตถุ)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");

คุณสามารถดูตัวอย่างที่ดีของเชนานิแกนรันไทม์ประเภทนี้ได้ในหนึ่งใน repos ของฉันที่นี่


5

ฉันรู้ว่ามีคำตอบมานานแล้ว แต่ฉันก็ยังอยากแบ่งปัน ซึ่งสามารถทำได้โดยใช้sel_registerNameเกินไป

โค้ดตัวอย่างในคำถามสามารถเขียนใหม่ได้ดังนี้:

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];

2
ที่จริงแล้วNSSelectorFromStringโดย @ torsten-marek ใช้sel_registerNameภายใต้ประทุน appledev : "NSSelectorFromString ส่งการแสดงอักขระที่เข้ารหัส UTF-8 ของ aSelectorName ไปยัง sel_registerName และส่งคืนค่าที่ส่งคืนโดยฟังก์ชันนั้น"
PLG
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.