@@ -164,10 +164,7 @@ public protocol HeadlessPlayer {
164
164
public extension HeadlessPlayer {
165
165
/// The current state of Player
166
166
var state : BaseFlowState ? {
167
- guard
168
- let jsState = jsPlayerReference? . invokeMethod ( " getState " , withArguments: [ ] )
169
- else { return nil }
170
- return BaseFlowState . createInstance ( value: jsState)
167
+ return jsPlayerReference? . getState ( )
171
168
}
172
169
173
170
/**
@@ -221,6 +218,10 @@ public extension HeadlessPlayer {
221
218
- completion: A completion handler for when the flow has completed
222
219
*/
223
220
func start( flow: String , completion: @escaping ( Result < CompletedState , PlayerError > ) -> Void ) {
221
+ // declare these variables outside and reference them inside the errorHandler to prevent retain cycle
222
+ let playerRef = jsPlayerReference
223
+ let loggerRef = logger
224
+
224
225
let promiseHandler : @convention ( block) ( JSValue ? ) -> Void = { completedState in
225
226
guard
226
227
let result = CompletedState . createInstance ( from: completedState)
@@ -231,17 +232,17 @@ public extension HeadlessPlayer {
231
232
}
232
233
let errorHandler : @convention ( block) ( JSValue ? ) -> Void = { _ in
233
234
guard
234
- let result = self . state as? ErrorState
235
- else {
235
+ let result = playerRef? . getState ( ) as? ErrorState else {
236
236
return completion ( . failure( PlayerError . jsConversionFailure) )
237
237
}
238
- logger. e ( result. error)
238
+
239
+ loggerRef. e ( result. error)
239
240
completion ( . failure( PlayerError . promiseRejected ( error: result) ) )
240
241
}
241
242
242
243
// Ensure these get created because otherwise we will never know when the flow ends/errors
243
244
guard
244
- let context = jsPlayerReference ? . context,
245
+ let context = playerRef ? . context,
245
246
let flowObject = context. evaluateScript ( " ( \( flow) ) " ) ,
246
247
!flowObject. isUndefined,
247
248
let callback = JSValue ( object: promiseHandler, in: context) ,
@@ -251,7 +252,7 @@ public extension HeadlessPlayer {
251
252
}
252
253
253
254
// Should not be possible due to fatalError in constructor, but just for handling optionals safely
254
- guard let player = jsPlayerReference else { return completion ( . failure( PlayerError . playerNotInstantiated) ) }
255
+ guard let player = playerRef else { return completion ( . failure( PlayerError . playerNotInstantiated) ) }
255
256
player
256
257
. invokeMethod ( " start " , withArguments: [ flowObject] )
257
258
. invokeMethod ( " then " , withArguments: [ callback] )
@@ -347,3 +348,12 @@ internal extension JSContext {
347
348
return value
348
349
}
349
350
}
351
+
352
+ private extension JSValue {
353
+ // put getState in extension so it can be accessed by the computed property in HeadlessPlayer.state and also inside the ErrorHandler by the playerReference
354
+ func getState( ) -> BaseFlowState ? {
355
+ guard let jsState = self . invokeMethod ( " getState " , withArguments: [ ] )
356
+ else { return nil }
357
+ return BaseFlowState . createInstance ( value: jsState)
358
+ }
359
+ }
0 commit comments