2013-10-05 4 views
5

मैं JSManagedValue का उपयोग करने का प्रयास करते समय समस्याओं में भाग रहा हूं। Session 615 at WWDC 2013 पर आधारित मेरी समझ से, जब आप ऑब्जेक्टिव-सी से जावास्क्रिप्ट में संदर्भ लेना चाहते हैं और इसके विपरीत, आपको संदर्भ चक्र से बचने के लिए उद्देश्य-सी में JSValue को संग्रहीत करने के बजाय JSManagedValue का उपयोग करना होगा।JSValue जारी किए बिना संदर्भ चक्र से बचने के लिए मैं JSManagedValue का उपयोग कैसे कर सकता हूं?

मैं जो करने का प्रयास कर रहा हूं उसका एक अलग-अलग संस्करण यहां दिया गया है। मेरे पास एक व्यू कंट्रोलर है जिसे जावास्क्रिप्ट ऑब्जेक्ट के संदर्भ की आवश्यकता है, और जावास्क्रिप्ट ऑब्जेक्ट को ViewController पर एक विधि कॉल करने में सक्षम होना चाहिए। व्यू कंट्रोलर में एक यूआईएलएबल है जो एक गिनती प्रदर्शित करता है, और इसमें दो UIButtons हैं, 'जोड़ें' जो गिनती को बढ़ाता है, और 'रीसेट' करता है, जो वर्तमान व्यू कंट्रोलर को एक नए व्यू कंट्रोलर के साथ बनाता है और बदल देता है (मूल रूप से बस मैं पुराने व्यू कंट्रोलर को सत्यापित कर सकता हूं जब मैं इसका परीक्षण कर रहा हूं, ठीक से साफ हो जाता है)।

viewDidLoad में, व्यू कंट्रोलर updateLabel पर कॉल करता है और जावास्क्रिप्ट ऑब्जेक्ट से गिनती को सही ढंग से प्राप्त करने में सक्षम है। हालांकि, उस रन लूप खत्म होने के बाद, इंस्ट्रूमेंट्स दिखा रहा है कि JSValue जारी हो रहा है। ViewController अभी भी मौजूद है, जैसा कि इसके JSManagedValue करता है, इसलिए मैंने सोचा कि JSValue को कचरा होने से रोकना चाहिए, लेकिन _managedValue.value अब शून्य लौटाता है।

यदि मैं JSManagedValue का उपयोग करने के बजाय JSValue को संग्रहीत करता हूं, तो यह सभी दृश्यमान रूप से काम करता है, लेकिन व्यू कंट्रोलर और जेएसवेल्यू के बीच एक संदर्भ चक्र है, जैसा कि अपेक्षित है, और इंस्ट्रूमेंट्स पुष्टि करता है कि व्यू कंट्रोलर कभी जारी नहीं किए जाते हैं।

जावास्क्रिप्ट कोड:

(function() { 
    var _count = 1; 
    var _view; 
    return { 
    add: function() { 
     _count++; 
     _view.updateLabel(); 
    }, 
    count: function() { 
     return _count; 
    }, 
    setView: function(view) { 
     _view = view; 
    } 
    }; 
})() 

CAViewController.h

@protocol CAViewExports <JSExport> 
- (void)updateLabel; 
@end 

@interface CAViewController : UIViewController<CAViewExports> 
@property (nonatomic, weak) IBOutlet UILabel *countLabel; 
@end 

CAViewController.m

@interface CAViewController() { 
    JSManagedValue *_managedValue; 
} 
@end 

@implementation CAViewController 

- (id)init { 
    if (self = [super init]) { 
     JSContext *context = [[JSContext alloc] init]; 

     JSValue *value = [context evaluateScript:@"...JS Code Shown Above..."]; 
     [value[@"setView"] callWithArguments:@[self]]; 

     _managedValue = [JSManagedValue managedValueWithValue:value]; 
     [context.virtualMachine addManagedReference:_managedValue withOwner:self]; 
    } 
    return self; 
} 

- (void)viewDidLoad { 
    [self updateLabel]; 
} 

- (void)updateLabel { 
    JSValue *countFunc = _managedValue.value[@"count"]; 
    JSValue *count = [countFunc callWithArguments:@[]]; 
    self.countLabel.text = [count toString]; 
} 

- (IBAction)add:(id)sender { 
    JSValue *addFunc = _managedValue.value[@"add"]; 
    [addFunc callWithArguments:@[]]; 
} 

- (IBAction)reset:(id)sender { 
    UIApplication *app = [UIApplication sharedApplication]; 
    CAAppDelegate *appDelegate = app.delegate; 
    CAViewController *vc = [[CAViewController alloc] init]; 
    appDelegate.window.rootViewController = vc; 
} 

क्या है इस सेटअप को संभालने का सही तरीका ताकि JSValue को ViewController के पूरे जीवनकाल में बरकरार रखा जा सके लेकिन कोई संदर्भ चक्र नहीं बनाया गया है ताकि ViewController को साफ़ किया जा सके?

उत्तर

1

मैं इससे भी उलझन में था। जावास्क्रिप्टकोर हेडर के साथ-साथ ColorMyWords नमूना प्रोजेक्ट पढ़ने के बाद, ऐसा लगता है कि प्रबंधित मूल्य के लिए इसके मूल्य को जीवंत रखने के लिए, स्वामी को जावास्क्रिप्ट (यानी, संदर्भ में किसी मान को असाइन किया गया) के लिए दृश्यमान होना चाहिए। आप ColorMyWords प्रोजेक्ट में AppDelegate.m की -loadColorsPlugin विधि में वर्णित यह देख सकते हैं।

+0

मुझे लगता है कि यह सही है। मुझे यह पुष्टि करने के लिए सत्र 615 के लिए वीडियो से स्रोत कोड को पढ़ने के लिए मजबूर होना पड़ता है हालांकि: नमूना प्रोजेक्ट अभी भी उपलब्ध होने पर यह अच्छा होगा। – Poulsbo

+0

नमूना कोड वर्तमान में यहां है: https://developer.apple.com/downloads/index.action?name=WWDC%202013 – Poulsbo

0

बस उत्सुक है, लेकिन क्या आपने अपने वर्ग के निजी इंटरफ़ेस में JSContext * संदर्भ और JSValue * मान गुण जोड़ने का प्रयास किया है?

मेरा झुकाव यह है कि आप अपने प्रारंभिकरण में जेएससीएन्टेक्स्ट * संदर्भ बना रहे हैं, लेकिन इसे बरकरार नहीं रखते हैं, इसलिए ऐसा लगता है कि आपके पूरे जेएससीएन्टेक्स्ट को एआरसी के साथ-साथ आपके JSValue * मान को कुछ अप्रत्याशित बिंदु पर एकत्र किया जा सकता है । लेकिन यह मुश्किल है क्योंकि आप इसे _managedValue के माध्यम से संदर्भित कर रहे हैं ...

मैं इस बारे में 100% निश्चित नहीं हूं, लेकिन मेरा अनुमान है कि आपको किसी प्रबंधित वाल्यू की आवश्यकता नहीं है। आप अपने कॉल के दौरान -(void)updateLabel पर जावास्क्रिप्ट से JSValue पास नहीं कर रहे हैं, जो कि डब्ल्यूडब्ल्यूडीसी में वर्णित स्पीकर समस्याग्रस्त होगा।इसके बजाय आपको क्या करना चाहिए, क्योंकि आपका कोड JSCalue * मान को आपके JSContext से संदर्भित कर रहा है, यह आपके .m में दोनों को अपने इंटरफ़ेस में जोड़ना है।

मैं यह भी ध्यान देता हूं कि आप गिनती फिर से लोड कर रहे हैं और जब भी आप ओबीजेसी विधियों को चलाते हैं तो जेएसवीएलयूएस में कार्यों को जोड़ते हैं। आप उन्हें कक्षा के हिस्से के रूप में ही रख सकते हैं ताकि वे केवल एक बार लोड हो जाएं।

तो बजाय:

@interface CAViewController() { 
    JSManagedValue *_managedValue; 
} 
@end 

यह होना चाहिए कुछ की तरह:

@interface CAViewController() 
@property JSContext *context; 
@property JSValue *value; 
@property JSValue *countFunc; 
@property JSValue *addFunc; 
@end 

और अपनी कक्षा के बाकी की तरह दिखना चाहिए:

@implementation CAViewController 

- (id)init { 
    self = [super init]; 
    if (self) { 
     _context = [[JSContext alloc] init]; 

     _value = [_context evaluateScript:@"...JS Code Shown Above..."]; 
     [_value[@"setView"] callWithArguments:@[self]]; 

     _addFunc = _value[@"add"]; 
     _countFunc = _value[@"count"]; 
    } 
    return self; 
} 

- (void)viewDidLoad { 
    [self updateLabel]; 
} 

- (void)updateLabel { 
    JSValue *count = [self.countFunc callWithArguments:@[]]; 
    self.countLabel.text = [count toString]; 
} 

- (IBAction)add:(id)sender { 
    [self.addFunc callWithArguments:@[]]; 
} 

- (IBAction)reset:(id)sender { 
    UIApplication *app = [UIApplication sharedApplication]; 
    CAAppDelegate *appDelegate = app.delegate; 
    CAViewController *vc = [[CAViewController alloc] init]; 
    appDelegate.window.rootViewController = vc; 
} 

जब से तुम आप चाहते हैं उल्लेख किया केवल ViewController को मारकर इसे साफ़ करने के लिए, JSContext और JSValue का कोई संदर्भ बी नहीं होगा पारिस्थितिकी वे भी ViewController के साथ जाना होगा (सिद्धांत में? : पी)।

उम्मीद है कि इससे मदद मिलती है। मैं उद्देश्य सी के लिए नया हूं (जावास्क्रिपकोर फ्रेमवर्क अकेले छोड़ दो) तो मैं वास्तव में रास्ता बंद कर सकता था!

संबंधित मुद्दे

 संबंधित मुद्दे