खोज…


टिप्पणियों

स्विफ्ट में विधि स्विज़लिंग का उपयोग करते समय दो आवश्यकताएँ हैं जिनका आपकी कक्षाओं / विधियों को पालन करना चाहिए:

  • आपकी कक्षा को NSObject विस्तार करना चाहिए
  • जिन कार्यों को आप स्वाइल करना चाहते हैं, उनमें dynamic विशेषता होनी चाहिए

यह क्यों आवश्यक है, इसकी पूरी व्याख्या के लिए, कोको और उद्देश्य-सी के साथ स्विफ्ट का उपयोग करके देखें :

डायनेमिक डिस्पैच की आवश्यकता

जबकि @objc विशेषता आपके स्विफ्ट एपीआई को ऑब्जेक्टिव-सी रनटाइम के लिए उजागर करती है, यह किसी प्रॉपर्टी, मेथड, सबस्क्रिप्ट या @objc डायनेमिक प्रेषण की गारंटी नहीं देता है। स्विफ्ट कंपाइलर अभी भी ऑब्जेक्टिव-सी रनटाइम को दरकिनार करते हुए, अपने कोड के प्रदर्शन को अनुकूलित करने के लिए सदस्य की पहुंच को निष्क्रिय या निष्क्रिय कर सकता है । जब आप dynamic संशोधक के साथ एक सदस्य की घोषणा को चिह्नित करते हैं, तो उस सदस्य तक पहुंच हमेशा गतिशील रूप से भेजी जाती है। क्योंकि dynamic संशोधक के साथ चिह्नित घोषणाएं उद्देश्य-सी क्रम का उपयोग करके प्रेषित की जाती हैं, वे स्पष्ट रूप से @objc विशेषता के साथ चिह्नित हैं।

गतिशील प्रेषण की आवश्यकता शायद ही कभी आवश्यक है। हालाँकि, आपको dynamic संशोधक का उपयोग करना चाहिए जब आप जानते हैं कि एपीआई के कार्यान्वयन को रनटाइम पर बदल दिया जाता है । उदाहरण के लिए, आप किसी एप्लिकेशन को चलाने के दौरान किसी पद्धति के कार्यान्वयन को स्वैप करने के लिए Object-C रनटाइम में method_exchangeImplementations फ़ंक्शन का उपयोग कर सकते हैं। यदि स्विफ्ट कंपाइलर ने विधि के कार्यान्वयन को रेखांकित किया है या इसके लिए उपयोग की अनुमति नहीं दी है, तो नए कार्यान्वयन का उपयोग नहीं किया जाएगा

लिंक

उद्देश्य-सी रनटाइम संदर्भ

NSHipster पर मेथड स्विज़लिंग

विस्तार UIViewController और Swizzling viewDidLoad

ऑब्जेक्टिव-सी में, विधि स्विज़लिंग एक मौजूदा चयनकर्ता के कार्यान्वयन को बदलने की प्रक्रिया है। यह उस तरह से संभव है, जिस तरह से चयनकर्ताओं को प्रेषण तालिका, या फ़ंक्शन या विधियों को इंगित करने वाली तालिका पर मैप किया जाता है।

शुद्ध स्विफ्ट विधियां गतिशील रूप से ऑब्जेक्टिव-सी रनटाइम द्वारा नहीं भेजी जाती हैं, लेकिन हम अभी भी NSObject से विरासत में प्राप्त किसी भी वर्ग पर इन ट्रिक्स का लाभ उठा सकते हैं।

यहां, हम कुछ कस्टम लॉगिंग को जोड़ने के लिए UIViewController और swizzle viewDidLoad का विस्तार करेंगे:

extension UIViewController {
    
    // We cannot override load like we could in Objective-C, so override initialize instead
    public override static func initialize() {
        
        // Make a static struct for our dispatch token so only one exists in memory
        struct Static {
            static var token: dispatch_once_t = 0
        }
        
        // Wrap this in a dispatch_once block so it is only run once
        dispatch_once(&Static.token) {
            // Get the original selectors and method implementations, and swap them with our new method
            let originalSelector = #selector(UIViewController.viewDidLoad)
            let swizzledSelector = #selector(UIViewController.myViewDidLoad)
            
            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
            
            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
            
            // class_addMethod can fail if used incorrectly or with invalid pointers, so check to make sure we were able to add the method to the lookup table successfully
            if didAddMethod {
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        }
    }
    
    // Our new viewDidLoad function
    // In this example, we are just logging the name of the function, but this can be used to run any custom code
    func myViewDidLoad() {
        // This is not recursive since we swapped the Selectors in initialize().
        // We cannot call super in an extension.
        self.myViewDidLoad()
        print(#function) // logs myViewDidLoad()
    }
}

स्विफ्ट स्विज़लिंग की मूल बातें

आइए हमारे TestSwizzling वर्ग में methodOne() और methodTwo() के कार्यान्वयन को स्वैप करें:

class TestSwizzling : NSObject {
    dynamic func methodOne()->Int{
        return 1
    }
}

extension TestSwizzling {
    
    //In Objective-C you'd perform the swizzling in load(), 
    //but this method is not permitted in Swift
    override class func initialize()
    {

        struct Inner {
            static let i: () = {

                let originalSelector = #selector(TestSwizzling.methodOne)
                let swizzledSelector = #selector(TestSwizzling.methodTwo)                 
                let originalMethod = class_getInstanceMethod(TestSwizzling.self, originalSelector);
                let swizzledMethod = class_getInstanceMethod(TestSwizzling.self, swizzledSelector)                
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
        let _ = Inner.i
    }
    
    func methodTwo()->Int{
        // It will not be a recursive call anymore after the swizzling
        return methodTwo()+1
    }
}

var c = TestSwizzling()
print(c.methodOne())
print(c.methodTwo())

स्वाज़लिंग की मूल बातें - उद्देश्य-सी

UIView के initWithFrame: पद्धति का उद्देश्य-सी उदाहरण

static IMP original_initWithFrame;

+ (void)swizzleMethods {
    static BOOL swizzled = NO;
    if (!swizzled) {
        swizzled = YES;

        Method initWithFrameMethod =
            class_getInstanceMethod([UIView class], @selector(initWithFrame:));
        original_initWithFrame = method_setImplementation(
            initWithFrameMethod, (IMP)replacement_initWithFrame);
    }
}

static id replacement_initWithFrame(id self, SEL _cmd, CGRect rect) {
    
    // This will be called instead of the original initWithFrame method on UIView
    // Do here whatever you need... 

    // Bonus: This is how you would call the original initWithFrame method
    UIView *view =
        ((id (*)(id, SEL, CGRect))original_initWithFrame)(self, _cmd, rect);

    return view;
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow