Ivan Ilic
07/12/2019, 1:14 PMlouiscad
07/12/2019, 7:33 PMIvan Ilic
07/15/2019, 9:21 AMsvyatoslav.scherbina
07/22/2019, 1:44 PMIvan Ilic
07/22/2019, 2:40 PMsvyatoslav.scherbina
07/22/2019, 2:44 PMIvan Ilic
07/22/2019, 2:57 PMIvan Ilic
07/24/2019, 11:21 AMobserveValueForKeyPath
function for catching new values.
Idea warns me that ‘observeValueForKeyPath’ overrides nothing.
Do you know how to do that?
Kotlin code
import kotlinx.cinterop.CValue
import platform.AVFoundation.*
import platform.CoreGraphics.CGRect
import platform.CoreGraphics.CGRectMake
import platform.Foundation.NSKeyValueObservingOptionNew
import platform.Foundation.NSURL
import platform.Foundation.addObserver
import platform.UIKit.UIView
import platform.darwin.NSObject
class PlayerOK {
private var observer = Observer()
private var asset: AVAsset
private var player: AVPlayer
private var playerItem: AVPlayerItem
private var playerLayer: AVPlayerLayer = AVPlayerLayer()
private val gcRect: CValue<CGRect> = CGRectMake(height = 100.0, width = 100.0, x = 20.0, y = 20.0)
val view: UIView = UIView(gcRect)
private val requiredAssetKeys = listOf("playable", "hasProtectedContent")
init {
val url =
NSURL(string = "<https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8>")
asset = AVAsset.assetWithURL(URL = url)
// Create a new AVPlayerItem with the asset and an
// array of asset keys to be automatically loaded
playerItem = AVPlayerItem(asset = asset, automaticallyLoadedAssetKeys = requiredAssetKeys)
// Register as an observer of the player item's status property
playerItem.addObserver(observer, forKeyPath = "status", options = NSKeyValueObservingOptionNew, context = null)
// Associate the player item with the player
player = AVPlayer(playerItem = playerItem)
playerLayer.player = player
playerLayer.frame = view.bounds
view.layer.addSublayer(playerLayer)
player.play()
}
}
class Observer : NSObject() {
fun observeValueForKeyPath(
keyPath: String?,
ofObject: Any?,
change: Map<Any?, *>?,
context: kotlinx.cinterop.COpaquePointer?
) {
println("keyPath $keyPath")
println("ofObject $ofObject")
println("change $change")
println("context $context")
}
}
Using in swift
class ViewController: UIViewController {
var c: PlayerOK?
override func viewDidLoad() {
super.viewDidLoad()
c = PlayerOK()
self.view.addSubview(c!.view)
}
}
Xcode error:
iosApp[3203:1352905] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<sample.Observer: 0x2801446d0>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: status
Observed object: <AVPlayerItem: 0x28014ba00, asset = <AVURLAsset: 0x280368d00, URL = <https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8>>>
Change: {
kind = 1;
new = 1;
}
Context: 0x0'
*** First throw call stack:
(0x209d7127c 0x208f4b9f8 0x209c7b4b0 0x20a7bc9b4 0x20a7bcb08 0x20a7bee9c 0x20a7bc3bc 0x20fca9f18 0x102cab6f0 0x102cacc74 0x102cba6fc 0x209d02c1c 0x209cfdb54 0x209cfd0b0 0x20befd79c 0x23652c978 0x1027c989c 0x2097c28e0)
libc++abi.dylib: terminating with uncaught exception of type NSException
Ivan Ilic
07/24/2019, 11:22 AMimport Foundation
import AVFoundation
import AVKit
class PlayerOK {
var observer:Observer = Observer()
var url: URL?
var asset: AVAsset?
var player: AVPlayer?
var playerItem: AVPlayerItem?
var playerLayer: AVPlayerLayer?
var view: UIView!
// Key-value observing context
private var playerItemContext = 3
let requiredAssetKeys = [
"playable",
"hasProtectedContent"
]
init(controller: UIViewController) {
let rect = CGRect(x: 0, y: 100, width: 100, height: 100)
view = UIView(frame: rect)
// Create the asset to play
url = URL(string: "<https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8>")
asset = AVAsset(url: url!)
// Create a new AVPlayerItem with the asset and an
// array of asset keys to be automatically loaded
playerItem = AVPlayerItem(asset: asset!,
automaticallyLoadedAssetKeys: requiredAssetKeys)
// Register as an observer of the player item's status property
playerItem?.addObserver(observer,
forKeyPath: #keyPath(AVPlayerItem.status),
options: [.old, .new],
context: &playerItemContext)
// Associate the player item with the player
player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = view.bounds
view.layer.addSublayer(playerLayer!)
player?.play()
}
}
class Observer: NSObject {
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
if keyPath == #keyPath(AVPlayerItem.status) {
let status: AVPlayerItem.Status
if let statusNumber = change?[.newKey] as? NSNumber {
status = AVPlayerItem.Status(rawValue: statusNumber.intValue)!
} else {
status = .unknown
}
// Switch over status value
switch status {
case .readyToPlay:
print("readyToPlay")
break
// Player item is ready to play.
case .failed:
print("failed")
break
// Player item failed. See error.
case .unknown:
print("unknown")
break
// Player item is not yet ready.
@unknown default:
print("Error")
}
}
}
}
ViewController:
import UIKit
class ViewController: UIViewController {
var c: PlayerOK?
override func viewDidLoad() {
super.viewDidLoad()
c = PlayerOK(controller: self)
self.view.addSubview(c!.view)
}
}
svyatoslav.scherbina
07/24/2019, 1:17 PMobserveValueForKeyPath
method could be a bit tricky.
It is originally declared as category method in Objective-C, thus imported as Kotlin extension which can’t be overridden.
To workaround this, you can configure interop with custom .def
file containing declaration of a protocol with this method, e.g. `observer.def`:
language = Objective-C
---
#import <Foundation/Foundation.h>
@protocol Observer
@required
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context;
@end;
and then inherit this protocol in Kotlin.Ivan Ilic
07/24/2019, 2:18 PMIvan Ilic
07/25/2019, 9:30 AMsvyatoslav.scherbina
07/25/2019, 11:54 AMlouiscad
07/26/2019, 7:51 AMdealloc
method in NSObject
?svyatoslav.scherbina
07/26/2019, 11:00 AMdealloc
is not possible for different reason.louiscad
07/26/2019, 11:33 AMsvyatoslav.scherbina
08/01/2019, 1:50 PMayodele
04/19/2023, 9:39 AMmessage was received but not handled
.Ivan Ilic
04/19/2023, 9:57 AMayodele
04/19/2023, 9:58 AM