我在嘗試使用JSManagedValue時遇到了問題。根據我對Session 615 at WWDC 2013的理解,當你想從Objective-C引用到Javascript時,反之亦然,你需要使用JSManagedValue,而不是隻在Objective-C中存儲JSValue以避免引用循環。如何在沒有JSValue的情況下使用JSManagedValue來避免引用週期?
這是我試圖做的簡化版本。我有一個ViewController,它需要一個JavaScript對象的引用,並且該JavaScript對象需要能夠在ViewController上調用一個方法。 ViewController有一個顯示計數的UILabel,它有兩個UIButtons,'Add'和Count',它們用來創建和替換當前視圖控制器和一個新的ViewController(基本上我可以驗證舊的ViewController當我測試這個時得到適當的清理)。
在viewDidLoad
中,ViewController調用updateLabel
,並且能夠正確地從JavaScript對象中獲取計數。但是,在運行循環結束之後,Instruments正在顯示JSValue正在發佈。 ViewController仍然存在,就像其JSManagedValue一樣,所以我認爲應該防止JSValue被垃圾收集,但是_managedValue.value
現在返回nil。
如果我只是存儲JSValue而不是使用JSManagedValue,它全部可視化,但ViewController和JSValue之間有一個引用循環,正如預期的那樣,並且Instruments確認ViewControllers永遠不會被釋放。
JavaScript代碼:
(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;
}
是什麼正確的方法來處理這個設置,以便在ViewController的整個生命週期中保留JSValue,但是沒有創建引用循環,這樣ViewController就可以清理了?
我認爲這是正確的。我不得不從會話615的視頻中讀取源代碼,以確認這一點:如果示例項目仍然可用,那將會很好。 – Poulsbo
示例代碼當前位於:https://developer.apple.com/downloads/index.action?name=WWDC%202013 – Poulsbo