// Copyright 2022-present 650 Industries. All rights reserved. #import #import @implementation EXJavaScriptWeakObject { /** Pointer to the `EXJavaScriptRuntime` wrapper. \note It must be weak because only then the original runtime can be safely deallocated when the JS engine wants to without unsetting it on each created object. */ __weak EXJavaScriptRuntime *_runtime; #if __has_include() /** A weak reference to a JS object. Available only on Hermes engine. */ std::shared_ptr _weakObject; #else /** Shared pointer to the `WeakRef` JS object. Available only on JSC engine. */ std::shared_ptr _weakObject; #endif } - (nonnull instancetype)initWith:(std::shared_ptr)jsObject runtime:(nonnull EXJavaScriptRuntime *)runtime { if (self = [super init]) { _runtime = runtime; #if __has_include() _weakObject = std::make_shared(*[runtime get], *jsObject); #else // Check whether the runtime supports `WeakRef` objects. If it does not, // we consciously hold a strong reference to the object and cause memory leaks. // This is the case on JSC prior to iOS 14.5. if (expo::isWeakRefSupported(*[runtime get])) { _weakObject = expo::createWeakRef(*[runtime get], jsObject); } else { _weakObject = jsObject; } #endif } return self; } - (nullable EXJavaScriptObject *)lock { jsi::Runtime *runtime = [_runtime get]; #if __has_include() jsi::Value value = _weakObject->lock(*runtime); // `lock` returns an undefined value if the underlying object no longer exists. if (value.isUndefined()) { return nil; } std::shared_ptr objectPtr = std::make_shared(value.asObject(*runtime)); #else std::shared_ptr objectPtr = expo::isWeakRefSupported(*runtime) ? expo::derefWeakRef(*runtime, _weakObject) : _weakObject; #endif if (!objectPtr) { return nil; } return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime]; } @end