รหัส Object-c สามารถเรียกส่วนขยายที่รวดเร็วในคลาสได้หรือไม่


102

ฉันค้นหาบางโพสต์ฉันคิดว่าฉันไม่สามารถเขียนส่วนขยายได้อย่างรวดเร็วและเรียกมันจากรหัส Objective-C ใช่ไหม?

@objc เช่นแอตทริบิวต์รองรับเฉพาะเมธอดคลาสโปรโตคอล?


1
ทำไมคุณไม่ลองดูล่ะ
HAS

7
ฉันบ่นข้อผิดพลาด แต่ฉันต้องการได้รับ anwser ที่แน่นอน
sprhawk

คำตอบ:


90

คุณสามารถเขียนส่วนขยาย Swift และใช้ในโค้ด Objective-C ทดสอบด้วย XCode 6.1.1

สิ่งที่คุณต้องทำคือ:

  • สร้างส่วนขยายของคุณใน Swift ( @objcจำเป็นต้องมีคำอธิบายประกอบตั้งแต่ Swift 4.0.3)

  • #import "ProjectTarget-Swift.h" ในคลาส Objective-C ของคุณ (โดยที่ "ProjectTarget" แสดงถึงเป้าหมาย XCode ที่ส่วนขยาย Swift เชื่อมโยงด้วย)

  • เรียกใช้วิธีการจากส่วนขยาย Swift


7
ฉันทำไปแล้ว แต่ก็ยังมีข้อผิดพลาดเกี่ยวกับเวลาคอมไพล์ อืม แก้ไข: ฉันนำเข้าส่วนหัวเชื่อมต่อแทน "ProjectTarget-Swift.h" เดอร์.
Jason Renaldo

ทั้งสองกำลังเชื่อมต่อส่วนหัว ความแตกต่างคือหนึ่งสำหรับการใช้รหัส Swift ใน ObjC และอีกอันใช้สำหรับการใช้รหัส ObjC ใน Swift ส่วนหัวของ Swift จะมองไม่เห็น อีกอันควรได้รับการจัดการโดยคุณ
marius bardan

William Hu ดูคำตอบของ mclaughlinj!
appleitung

40
สำหรับ Swift 4.0.3 จำเป็นต้องมีคำอธิบายประกอบ @objc หากคุณต้องการใช้ส่วนขยายในไฟล์คลาส Objective C
Rizwan Ahmed

หมายเหตุ: หากชื่อของเป้าหมายโครงการของคุณมีเครื่องหมายขีดกลางแสดงว่าเส้นประจะต้องถูกลบออกจากคำสั่งนำเข้า ตัวอย่างเช่นหากชื่อเป้าหมายโครงการของคุณคือ "project-target" คำสั่งนำเข้าควรอ่าน "projecttarget-Swift.h"
Tyler Wood

73

ฉันพบว่าในSwift 4.0ฉันต้องเพิ่ม@objcหน้าคำหลักส่วนขยายของฉันเพื่อให้วิธีการขยาย Swift สามารถมองเห็นได้โดยอินสแตนซ์ของคลาส Objc ที่ฉันกำลังขยาย

ในระยะสั้น:

การตั้งค่าการกำหนดค่าไฟล์:

CustomClass.h
CustomClass.m
CustomClassExtension.swift

ใน CustomClassExtension:

@objc extension CustomClass
{
    func method1() 
    {
        ...
    }
}

ใน AppDelegate.m ของฉัน:

self.customClass = [[CustomClass alloc] init];
[self.customClass method1];

2
ถ้าเมธอดใช้ generics จะไม่สามารถใช้ Objective-C ได้และคุณจะต้องเพิ่ม@nonobjcคำอธิบายประกอบ
ThomasW

ในกรณีนี้ @objcMembers ไม่สามารถใช้งานได้ ไม่รู้ทำไม .. :-(
Raunak

49

การแก้ปัญหานี้ทำงานให้กับสวิฟท์สวิฟท์ 2.2 และ 3 โปรดทราบว่าเฉพาะส่วนขยายสำหรับคลาส (ไม่ใช่สำหรับโครงสร้างหรือ enums) เท่านั้นที่สามารถเข้าถึงได้จาก Objective-C

import UIKit

extension UIColor {

    //Custom colours
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

จากนั้น#import "ProductModuleName-Swift.h"ในไฟล์ ObjC ของคุณ

สวิฟต์ 4

extension UIColor {

    // As of Swift 4.0.3, the @objc annotation is needed if you want to use the extension in Objective-C files
    @objc
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

ไม่ใช่ "YourProjectsNameHere ... " แต่เป็น "YourTargetsNameHere ... ": หากต้องการแชร์เป้าหมายคุณต้องล็อกเป็นชื่อ: dr2050.postach.io/post/…
Dan Rosenstark

1
@DanRosenstark คุณถูกต้อง ฉันกำลังเปลี่ยนเป็น "ProductModuleName-Swift.h" ตามที่ Apple แนะนำ: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
Foti Dim

1
ใช้งานได้ดีสำหรับ Swift 3
Viktor Kucera

มีเหตุผลอะไรที่คุณบอกว่าpublicจำเป็น? ทำงานได้ดีโดยไม่ต้องpublicปรับเปลี่ยนสำหรับฉัน เราสมมติว่าส่วนขยายไม่ได้อยู่ในโครงการเดียวกัน แต่นำเข้าจากโครงการอื่นหรือไม่?
Lee Kang

ฉันต้องใช้ bridging header หรือไม่?
jegadeesh

42

ในฐานะที่เป็นที่กล่าวถึงในคำตอบอื่น ๆ นำเข้าที่สร้างผลงานสวิฟท์ส่วนหัวในกรณีส่วนใหญ่

ข้อยกเว้นคือเมื่อมีการกำหนดหมวดหมู่ในประเภทบริดจ์ (กล่าวคือส่วนขยายถูกกำหนดไว้ที่Stringและไม่ใช่NSString) หมวดหมู่เหล่านี้จะไม่เชื่อมโยงกับ Objective-C โดยอัตโนมัติ ในการแก้ไขปัญหานี้คุณอาจต้องใช้ประเภท Objective-C (และส่งค่าส่งคืนในโค้ด Swift ด้วยas String) หรือกำหนดส่วนขยายสำหรับทั้งประเภท Swift และ Objective-C


2
เพิ่มคำตอบข้างต้นคุณควรทำให้ประชาชนส่วนขยายอย่างรวดเร็วของคุณและตั้งค่าชนิดของมันเป็น NSString public extension NSStringเช่น หากคุณได้รับตัวระบุที่ไม่ได้รับการแก้ไขหรือข้อผิดพลาดที่คล้ายกันในเวลาคอมไพล์คุณสามารถส่งอีกครั้งกลับไปที่ String เช่นlet sVal = self as Stringจากนั้นเรียกรหัสที่จำเป็นบนsVal
RunLoop

@RunLoop ที่จริงคุณไม่ต้องการสาธารณะมันจะทำงานได้โดยไม่ต้องระบุขอบเขต และมัน (ส่งออกไปยัง Obj-C ฉันหมายถึง) ใช้ไม่ได้กับ Strings เนื่องจากเป็นโครงสร้างไม่ใช่คลาสและมีให้จาก Swift เท่านั้น ใช่ - คุณสามารถเขียนส่วนขยายสำหรับ NSString และใช้ cast หรือเขียนส่วนขยายได้ตามที่mclaughlinjกล่าวไว้สำหรับทั้งคลาส NSString และ String struct
Alex Nazarsky

3

นำเข้า "#import 'ProductModuleName-Swift.h'ส่วนหัวในวัตถุประสงค์ -c ไฟล์และเพิ่ม@objcหน้าของคุณextentsionในไฟล์ที่รวดเร็ว. มันจะทำงานได้ดีในสวิฟท์ 4.2 และรวดเร็ว 5


1

หากคิดว่าคุณได้กำหนดค่าทุกอย่างถูกต้อง (ทำเครื่องหมายเอนทิตี Swift ของคุณด้วย @objcMembers หรือ @objc ให้นำเข้าส่วนหัวเชื่อม "ProductModuleName-Swift.h" และอื่น ๆ ) - แต่ยังคงได้รับNo visible @interface for 'FooClass' declares the selector 'fooSelector'ข้อผิดพลาด:

ตรวจสอบว่าคุณเห็นอินเทอร์เฟซของคุณในส่วนหัวเชื่อมต่อหรือไม่โดยctrl + cmdคลิกที่อินเทอร์เฟซ หากไม่เป็นเช่นนั้นโปรดดูคำตอบของฉันสำหรับคำถามนี้: ส่วนหัว Swift to Objective-C ไม่มีคลาส Swift

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