यह मेरे मुख्य लक्ष्य में मेरा कोड है (इसलिए परीक्षण लक्ष्य नहीं):

protocol ProtocolA {
    func dontCrash()
}

extension ProtocolA {
    func dontCrash() {
        fatalError()
    }

    func tryCrash() {
        dontCrash()
    }
}

class MyClass: ProtocolA {}

मेरे परीक्षण लक्ष्य (इतना अलग लक्ष्य) में, मुझे यह कोड मिला:

import XCTest
@testable import Project

extension MyClass {
    func dontCrash() {
        print("I dont crash")
    }
}

class ProjectTests: XCTestCase {
    func testExample() {
        MyClass().tryCrash()
    }
}

यह दुर्घटनाग्रस्त हो जाता है। यह गतिशील प्रेषण तंत्र का उपयोग क्यों नहीं करता है? MyClass के पास dontCrash() का अपना कार्यान्वयन है, मुझे उम्मीद है कि एक आग लग जाएगी।

3
J. Doe 26 नवम्बर 2018, 22:14

1 उत्तर

सबसे बढ़िया उत्तर

आपका Project मॉड्यूल MyClass के ProtocolA के अनुरूप होने की घोषणा करता है।

स्विफ्ट लागू करता है कि "प्रोटोकॉल गवाह तालिका" नामक डेटा संरचना का उपयोग करके अनुरूपता। प्रोटोकॉल द्वारा घोषित प्रत्येक विधि के लिए, गवाह तालिका में एक फ़ंक्शन होता है जो कि अनुरूप प्रकार के लिए विधि के वास्तविक कार्यान्वयन को कॉल करता है।

ठोस होने के लिए, MyClass से ProtocolA के अनुरूपता के लिए एक साक्षी तालिका है। उस साक्षी तालिका में ProtocolA द्वारा घोषित dontCrash विधि के लिए एक फ़ंक्शन है। साक्षी तालिका में वह फ़ंक्शन MyClass dontCrash विधि कहता है।

जब आपका टेस्ट केस fatalError हिट होता है, तो आप स्टैक ट्रेस में प्रोटोकॉल गवाह तालिका से फ़ंक्शन देख सकते हैं:

#8  0x00000001003ab9d9 in _assertionFailure(_:_:file:line:flags:) ()
#9  0x00000001000016fc in ProtocolA.dontCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:11
#10 0x0000000100001868 in protocol witness for ProtocolA.dontCrash() in conformance MyClass ()
#11 0x000000010000171e in ProtocolA.tryCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:15
#12 0x00000001030f1987 in ProjectTests.testExample() at /Users/rmayoff/TestProjects/Project/ProjectTests/ProjectTests.swift:12
#13 0x00000001030f19c4 in @objc ProjectTests.testExample() ()

फ़्रेम #10 tryCrash से प्रोटोकॉल गवाह तालिका में फ़ंक्शन के लिए कॉल है। फ़्रेम #9 प्रोटोकॉल गवाह तालिका फ़ंक्शन से dontCrash के वास्तविक कार्यान्वयन के लिए कॉल है।

स्विफ्ट उस मॉड्यूल में प्रोटोकॉल गवाह तालिका का उत्सर्जन करता है जो अनुरूपता की घोषणा करता है। तो, आपके मामले में, गवाह तालिका Project मॉड्यूल का हिस्सा है।

आपके परीक्षण बंडल में dontCrash का आपका ओवरराइड गवाह तालिका की सामग्री को नहीं बदल सकता है। इसके लिए बहुत देर हो चुकी है। गवाह तालिका पूरी तरह से परिभाषित थी जब स्विफ्ट ने Project मॉड्यूल उत्पन्न किया।

यहां बताया गया है कि इसे इस तरह क्यों होना चाहिए:

मान लीजिए मैं Project मॉड्यूल का लेखक हूं और आप इसके केवल एक उपयोगकर्ता हैं। जब मैंने Project मॉड्यूल लिखा था, मुझे पता था कि MyClass().dontCrash() को कॉल करना fatalError होगा, और मैं इस व्यवहार पर निर्भर था। Project के अंदर कई जगहों पर, मैंने विशेष रूप से MyClass().dontCrash() को कॉल किया क्योंकि मुझे पता था कि यह fatalError को कॉल करेगा। आप, Project के उपयोगकर्ता के रूप में, यह नहीं जानते कि Project उस व्यवहार पर कितना निर्भर करता है।

अब आप अपने ऐप में Project मॉड्यूल का उपयोग करते हैं, लेकिन आप पूर्वव्यापी रूप से MyClass().dontCrash() को कॉल न करने के लिए fatalError में बदल देते हैं। अब वे सभी स्थान जहां Project कॉल MyClass().dontCrash() उस तरह से व्यवहार नहीं करते जैसा मैंने Project मॉड्यूल लिखते समय अपेक्षित था। आपने Project मॉड्यूल को तोड़ दिया है, भले ही आपने Project मॉड्यूल के स्रोत कोड या Project आयात करने वाले किसी भी मॉड्यूल को नहीं बदला है।

Project मॉड्यूल के सही संचालन के लिए यह महत्वपूर्ण है कि ऐसा न हो। तो MyClass().dontCrash() का मतलब (जब Project मॉड्यूल के अंदर से कॉल किया जाता है) को बदलने का एकमात्र तरीका Project मॉड्यूल के स्रोत कोड को बदलना है (या किसी चीज़ का स्रोत कोड बदलना है जो Project आयात)।

1
rob mayoff 26 नवम्बर 2018, 20:28