2015-06-18 12 views
6

क्या यह निर्दिष्ट करने का कोई तरीका है कि किसी विशेष विधि तर्क में कमजोर अर्थशास्त्र है?कमजोर विधि तर्क अर्थशास्त्र

- (void)runTest { 
    __block NSObject *object = [NSObject new]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self myMethod:object]; 
    }); 
    // to make sure it happens after `myMethod:` call 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     object = nil; 
    }); 
} 
- (void)myMethod:(__weak id)arg0 { 
    NSLog(@"%@", arg0); // <NSObject: 0x7fb0bdb1eaa0> 
    sleep(1); 
    NSLog(@"%@", arg0); // nil 
} 

यह स्विफ्ट संस्करण, कि नहीं करता है

public func runTest() { 
    var object: NSObject? = NSObject() 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     self.myMethod(object) 
    } 
    dispatch_async(dispatch_get_main_queue()) { 
     object = nil 
    } 
} 
private func myMethod(arg0: AnyObject?) { 
    println("\(arg0)") //Optional(<NSObject: 0x7fc778f26cf0>) 
    sleep(1) 
    println("\(arg0)") //Optional(<NSObject: 0x7fc778f26cf0>) 
} 

मैं ym धारणा में सही हूँ है:

विस्तार से बता दें कि यह एक ऑब्जेक्टिव-सी नमूना कोड है कि उम्मीद के रूप में काम करता है स्विफ्ट संस्करण में विधि कॉल के बीच arg0 बनने के लिए कोई रास्ता नहीं है? धन्यवाद!

अद्यतन एप्पल Dev.Forums से किसी उपयोगकर्ता ने बताया कि sleep प्रयोग करने में और लगातार डिस्पैच रेस स्थितियां कारण हो सकता है एक अच्छा काम नहीं है। हालांकि वे उचित चिंताओं हो सकते हैं, यह सिर्फ एक नमूना कोड है, सवाल का ध्यान कमजोर तर्कों को पारित करने पर है।

+0

फिलहाल यह संभव नहीं है, आप इसे बंद करने की शुरुआत में '[कमजोर yourObject]' के साथ स्विफ्ट 2.0 से पहले कर सकते हैं। यह भी देखें [यहां] (http://stackoverflow.com/questions/24717460/cant-make-weak-reference-to-closure-in-swift) जहां वे कुछ वर्कअराउंड दिखाते हैं – Kametrixom

+0

मैं समझता हूं कि कमजोर बंद होना समाधान हो सकता है लेकिन यह समस्या का समाधान नहीं करता है, मैं नहीं चाहता कि एपीआई के सभी उपभोक्ताओं को मेरे कार्यान्वयन विवरणों के बारे में पता होना चाहिए। क्या स्विफ्ट 2 में यह संभव है? –

+0

उपभोक्ताओं को इस तरह के आपके एपीआई कार्यान्वयन के बारे में कैसे पता चलेगा? – Kametrixom

उत्तर

1

क्या यह निर्दिष्ट करने का कोई तरीका है कि किसी विशेष विधि तर्क में कमजोर अर्थशास्त्र है?

यह नहीं है कि आपका उद्देश्य-सी कोड उदाहरण क्या कर रहा है। आप गलती से लगभग कमजोर अर्थशास्त्र प्राप्त कर रहे हैं और आपके पास अपरिभाषित व्यवहार (दौड़ की स्थिति) है जो असली कमजोर संदर्भ नहीं है।

myMethod किसी भी क्रम बिंदु (पहले NSLog बयान या दूसरे, या यहाँ तक NSLog के बीच कहीं पर ला-ला-भूमि में एक संदेश भेज सकते ... भले ही एआरसी आप arg0 के बनाए रखने छिपाना नहीं है अभी भी मुख्य कतार रिलीज या बदतर रेसिंग कर रहे हैं - एक ज़ोंबी ऑब्जेक्ट को बनाए रखना)।

__block के रूप में कुछ की घोषणा सिर्फ ब्लॉक के लिए ढेर वातावरण में एक स्लॉट आवंटित (क्योंकि dispatch_async ब्लॉक से बच यह एक ढेर ब्लॉक करने के लिए एक ढेर-आवंटित ब्लॉक से बढ़ावा देंगे जाने के लिए गारंटी है इसका मतलब है, और भंडारण स्लॉट में से एक उस ढेर ब्लॉक वातावरण में आपके __block चर के लिए होगा। एआरसी के तहत ब्लॉक में स्वचालित रूप से Block_copy कहा जाएगा, शायद अधिक उपयुक्त नाम Block_copy_to_heap)।

इसका मतलब है कि ब्लॉक के निष्पादन उदाहरण दोनों ही स्मृति स्थान को इंगित करेंगे।

यदि यह मदद करता है, तो इस वास्तव में मूर्ख कोड की कल्पना करें जिसमें एक स्पष्ट दौड़ की स्थिति है। unsafe को संशोधित करने की कोशिश कर रहे सभी 1000 कतारबद्ध रूप से कतारबद्ध हैं। हम लगभग ब्लॉक के अंदर ग़लत बयान निष्पादित करने की गारंटी देते हैं क्योंकि हमारा असाइनमेंट और तुलना परमाणु नहीं है और हम उसी स्मृति स्थान पर लड़ रहे हैं।

static volatile size_t unsafe = 0; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

    dispatch_apply(1000, queue, ^(size_t instance) { 
     unsafe = instance; 
     if (unsafe != instance) { 
      FORMAT_ALL_STORAGE(); 
      SEND_RESIGNATION_EMAIL(); 
      WATCH_THE_WORLD_BURN(); 
     } 
    }); 

आपका स्विफ्ट उदाहरण क्योंकि ब्लॉक कि मूल्य संशोधित नहीं करता है शायद कब्जा (और बरकरार रखती है) वस्तु इतनी अन्य ब्लॉक से संशोधन नहीं देखता ही समस्या नहीं है।

यह एक बंद के निर्माता स्मृति प्रबंधन परिणामों से निपटने के तो आप एक API अनुबंध है कि लागू करता है कोई एक बंद में चक्र को बनाए रखने, @noescape जिसमें मामले स्विफ्ट जीता 'के रूप में कुछ अंकन के अलावा अन्य नहीं बना सकते पर निर्भर है कोई भी बनाए रखने/रिलीज या अन्य मेमोरी प्रबंधन करते हैं क्योंकि ब्लॉक वर्तमान स्टैक फ्रेम से बाहर नहीं निकलता है। यह स्पष्ट कारणों से async प्रेषण को रोकता है।

यदि आप एक एपीआई अनुबंध पेश करना चाहते हैं जो हल करता है तो आप एक प्रकार का प्रोटोकॉल protocol Consumer: class { func consume(thing: Type) } अपना सकते हैं तो आपके एपीआई के अंदर Consumer उदाहरणों के लिए एक कमजोर संदर्भ रखें।

एक और तकनीक एक उदाहरण समारोह की एक curried संस्करण को स्वीकार करने और दुर्बलता से कब्जा self है:

protocol Protocol: class { } 
typealias FuncType =() -> Void 
var _responders = [FuncType]() 

func registerResponder<P: Protocol>(responder: P, usingHandler handler: (P) ->() -> Void) { 
    _responders.append({ [weak responder] in 
     guard let responder = responder else { return } 
     handler(responder)() 
    }) 
} 

class Inst: Protocol { 
    func myFunc() { 

    } 
} 
let inst = Inst() 
registerResponder(inst, usingHandler: Inst.myFunc) 
+0

मुझे यकीन नहीं है कि यह प्रश्न – doozMen

+0

तकनीकी रूप से आप सही हैं क्योंकि मूल प्रश्न वास्तव में क्या चल रहा था और इसमें थ्रेड और मेमोरी सुरक्षा त्रुटियों की एक गलतफहमी पर आधारित है; कमजोर विधि पैरामीटर जैसी कोई चीज़ नहीं है जिसे मैंने अपने उत्तर में स्पष्ट रूप से समझाने की कोशिश की। मैंने सोचा कि विस्तार से व्याख्या करना फायदेमंद होगा ताकि हर कोई सीख सके। – russbishop

+0

@russbishop अगर "कमजोर विधि पैरामीटर जैसी कोई चीज़ नहीं है" तो संकलक विधि पैरामीटर पर '__weak' कीवर्ड क्यों अनुमति देता है? आम तौर पर, क्लैंग त्रुटियों को फेंकता है अगर आप गलत जगहों पर क्वॉर्ड्स डालते हैं। –

6

स्विफ्ट "कमजोर आर्ग" नहीं है ... लेकिन यह है कि शायद इसलिए है क्योंकि स्विफ्ट (3.0) आर्ग अपरिवर्तनीय हैं (let एस के बराबर) और weak स्विफ्ट में चीजें var और Optional दोनों की आवश्यकता है।

यानी, वास्तव में एक सुंदर-आसान तरीका कमजोर args- उपयोग करने के लिए एक बराबर पूरा करने के लिए है एक weak var स्थानीय (जो आर्ग-वर जारी होने की भी मुक्त हो)। यह काम करता है क्योंकि स्विफ्ट वर्तमान दायरे के अंत तक वर्रों पर लटका नहीं है (जैसे सी ++ इतना सख्ती से करता है); बल्कि यह (जो lldb बनाता है-कभी-कभी पीआईटीए को भी बनाता है, लेकिन जो भी हो) के आखिरी उपयोग के बाद यह दायरे से वर्से जारी करता है।

निम्न उदाहरण MacOS 10.11.6 पर Xcode 8.2.1 पर स्विफ्ट 3.0.2 में लगातार काम करता है:

class Test 
{ 
    func runTest() { 
     var object:NSObject? = NSObject() 
     myMethod(arg0: object) 

     DispatchQueue.main.asyncAfter(
      deadline: DispatchTime.now() + 1.0, 
      qos: .userInteractive, 
      flags: DispatchWorkItemFlags.enforceQoS 
     ){ 
      object = nil 
     } 
    } 

    func myMethod(arg0:AnyObject?) { 
     weak var arg0Weak = arg0 
     // `arg0` get “released” at this point.  Note: It's essential that you 
     // don't use `arg0` in the rest of this method; only use `arg0Weak`. 

     NSLog("\(arg0Weak)"); // Optional(<NSObject: 0x600000000810>) 

     DispatchQueue.main.asyncAfter(
      deadline: DispatchTime.now() + 2.0, 
      qos: .userInteractive, 
      flags: DispatchWorkItemFlags.enforceQoS 
     ){ 
      NSLog("\(arg0Weak)"); // nil 
     } 
    } 
} 

Test().runTest() 

ध्यान दें कि यदि आप एक खेल का मैदान में इस कोशिश, खेल का मैदान से पहले निष्पादन खत्म हो जाएगा DispatchQueue एस आग। निष्पादन योग्य को अनिश्चित काल तक चलाने का सबसे आसान तरीका (मैंने जो किया) एक नया कोको एप्लिकेशन बना रहा है और ऊपर दिए गए सभी कोड को func applicationDidFinishLaunching(_:Notification) { … }(हां, वर्बैटिम-स्विफ्ट विधियों के अंदर घोंसला वाली कक्षा परिभाषाओं को अनुमति देता है)


के जवाब में धागे की सुरक्षा-व्याख्यान देने आप अपने उदाहरण में dispatch_async & sleep का उपयोग कर, कि कमजोर आर्ग साबित करने के लिए अधिक मिल गया है कर रहे हैं वास्तव में असली सौदा यहाँ एक complete- main.m स्रोत संस्करण है आपके परीक्षण का एकल-थ्रेडेड और कतार-मुक्त:

#import <Foundation/Foundation.h> 


@interface Test : NSObject 
- (void)runTest; 
- (void)myMethod:(__weak id)arg0 callback:(void (^)())callback; 
@end 


int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     [[Test new] runTest]; 
    } 
    return 0; 
} 


@implementation Test 

- (void)runTest { 
    __block NSObject *object = [NSObject new]; 
    [self myMethod:object callback:^{ 
     object = nil; 
    }]; 
} 

- (void)myMethod:(__weak id)arg0 callback:(void (^)())callback { 
    NSLog(@"%@", arg0); // <NSObject: 0x100400bc0> 
    callback(); 
    NSLog(@"%@", arg0); // (null) 
} 

@end 
+0

मेरा मानना ​​है कि आप तर्क को छाया से पुन: उपयोग से भी बच सकते हैं: यानी कमजोर var arg0 = arg0 –

+0

मेरा परीक्षण इस मामले के लिए विफल रहता है: https://gist.github.com/garvankeeley/e85c2adb8e3079e4fe3c17ae62df478c –

+0

"यह काम करता है क्योंकि स्विफ्ट लटका नहीं है वर्तमान दायरे के अंत तक वर्रों पर "-> क्या आपके पास इसके लिए दस्तावेज़ हैं? –

2

अब भाषा वाक्यविन्यास के साथ कोई रास्ता नहीं है।

मुझे लगता है कि यह कामकाज अब के लिए निकटतम है।

public struct Weak<T> where T: AnyObject { 
    public weak var object: T? 

    public init(_ object: T?) { 
     self.object = object 
    } 
} 

func run(_ a: Weak<A>) { 
    guard let a = a.object else { return } 
} 
संबंधित मुद्दे