Let me explain, what I am trying to achieve in short.
In iOS app, trying to take the Photo, with certain amount of torch level for e.g. 0.7, as below.
myDevice?.setTorchModeOnWithLevel(0.7)
When we take photo, with this settings, I can see the torch light intensity. But sometimes, we are getting dull or bright photos (independent of external light conditions).
Hence to check the exact issue, we want to measure torch intensity, tried to use key value observer for torchLevel property of AVCaptureDevice, but this value seems to be unchanged.
Below is the sample code.
self.myDevice?.addObserver(self, forKeyPath: "torchLevel", options: .new, context: nil);
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath=="torchLevel"
{
print(myDevice.torchLevel)
}
}
So not sure, whether iPhone 7's torch having some issue, when accessing from swift API ?
Already checked this, but no answer.
Related
I am trying to play a 4k Video in the AVPlayer with Swift 3 for iOS12 and it works totally fine, but i want this video to play inside a loop. I found articles that stated, that you should use this method to register for the end of the video playback:
NotificationCenter.default.addObserver(self, selector: #selector(self.replay),
name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
In this case self.replay is beeing called once the player reached the end of the video. This works fine for normal videos, but once i try to play a ~4 second long video it does not loop.
The replay function looks like this:
#objc func replay() {
self.playerViewController!.player?.seek(to: CMTime.zero)
self.playerViewController!.player!.playImmediately(atRate: 1)
}
Im adding the Observer in the presenting ViewController's viewDidLoad.
Is this a race-condition, because as stated longer videos work fine? How can i prevent this behaviour.
(Sidenote: Not a regular poster, so please tell me if my question is asked wrong or hard to understand)
NotificationCenter.default.addObserver(self, selector: #selector(replay),
name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
#objc func replay() {
self.playerViewController!.player!.seek(to: CMTime.zero)
self.playerViewController!.player!.play()
}
Not sure what playImmediately(atRate:) does, however, I know in my experience playing videos on loop is to reset the player to time zero, as you have done. Then, just naturally play the video.
ADDITION: On another note, you can WAIT until the video is ready to play to add the observer AND start the video.
override func viewDidLoad() {
player.addObserver(self, forKeyPath: "status", options: [], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if(keyPath == "status" && self.playerViewController!.player!.status == .readyToPlay) {
NotificationCenter.default.addObserver(self, selector: #selector(replay), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
self.playerViewController!.player!.play()
}
}
I've tried implementing other code on stackoverflow with no luck. I'm evaluating javascript in a WKWeview, and would like to listen for when the content has fully loaded in order to execute statements on the loaded page.
Javascript: (isn't executing func webView)
webView.evaluateJavaScript("_formHist.submit();", completionHandler: nil)
Code I've tried using so far: (only works on some pages)
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
//insert code
}
I'm new to iOS development, so please explain answers in depth if you can!
How is _formHist defined??
If this isn't defined as a javascript object already, it won't work.
Apart from that, the page may not be fully loaded at the time the code is executed so you may need to listen to an event that is triggered when the page is fully loaded
If you refer to this answer it tells you that you can determine when the page has fully loaded using the following method
document.addEventListener("DOMContentLoaded", function(event) {
//do work
});
So for your case, you just need to use this event listener
webView.evaluateJavaScript("document.addEventListener("DOMContentLoaded", function(event) { _formHist.submit(); });", completionHandler: nil)
Give that a try and see if it works
Maybe you would like to make it much advanced and simple at the same time, so you can show the estimation progress for the user and sure then you can detect that everything was loaded and finished so you can do whatever you want. here's how you can do it:
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "estimatedProgress" {
print(Float(webView.estimatedProgress))
//Do whatever you want when finished
}
}
I want to monitor watch battery state so i have added KVO for battery state like this
private func setupNotification() {
WKInterfaceDevice.current().addObserver(self,
forKeyPath: #keyPath(WKInterfaceDevice.batteryState),
options: [.new],
context: nil)
}
override public func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?) {
if keyPath == #keyPath(WKInterfaceDevice.batteryState) {
switch WKInterfaceDevice.current().batteryState {
case .charging:
self.stopMonitoring()
case .unplugged:
if BatteryManager.batteryLevel > Constant.Battery.criticalValue {
self.startMonitoring()
}
default:
break
}
}
}
Also I have added before
func enableBatteryMonitoring() {
WKInterfaceDevice.current().isBatteryMonitoringEnabled = true
}
But it's not getting called, when in/out plug charger.
Any permission or else what i'm missing?
As far as I saw from the documentation is not stated clearly that this property is KVO compliant.
In the WatchKit documentation they say:
If battery monitoring is enabled, this property is set to a value
between 0.0 (0% charge) and 1.0 (100% charge). When the batteryState
property is set to WKInterfaceDeviceBatteryState.unknown (for example,
when battery monitoring is disabled), the value is -1.0.
So it seems that isBatteryMonitoringEnabled it just enable you to read the battery by asking its value (by polling) instead of observing it.
This question already has answers here:
KVO broken in iOS 9.3
(3 answers)
Closed 5 years ago.
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("in viewDidLoad");
// addObserver keyPath
UserDefaults.standard.addObserver(self, forKeyPath: "testKey", options: .new, context: nil);
print("out viewDidLoad");
}
deinit {
// removeObserver keyPath
UserDefaults.standard.removeObserver(self, forKeyPath: "testKey");
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("in observeValue keyPath: \(keyPath) value: \(UserDefaults.standard.integer(forKey: "testKey"))");
// 1. If I execute the func click () method, it will be executed two times
// 2. If App originally existed "testKey", then func observeValue () will be executed after the viewDidLoad is finished.
}
#IBAction func click(_ sender: NSButton) {
UserDefaults.standard.set(arc4random(), forKey: "testKey");
}
}
The above code is all of my test code. I used KVO in my own project, but found repeated execution.
// 1. If I execute the func click () method, it will be executed two times
// 2. If App originally existed "testKey", then func observeValue () will be executed after the viewDidLoad is finished.
This is not what I understand about KVO. My idea is that after addObserver, my observeValue will be called if my key is changed. But it didn't turn out that way. I tried to find the answer to the forum, and I didn't find the answer. I just found a similar question.
If I press Button in my view, then the final result will be..:
in viewDidLoad
out viewDidLoad
in observeValue keyPath: Optional("testKey") value: 4112410111
in observeValue keyPath: Optional("testKey") value: 3712484288
in observeValue keyPath: Optional("testKey") value: 3712484288
macos: 10.12.6 (16G29)
xcode: 9 beta6、xcode 8.3.3
If you have the same problem, please tell more people to help us solve it. Thank you
I have sent the same question to the official, and if there is a solution, I will return it here.
From setting a breakpoint in observeValue() and looking at the trace, it appears that the observations are getting fired in two places; one during click() as an effect of the line where you tell UserDefaults to set the value, and another later on, scheduled on the run loop so it happens after click() has already returned, when the system detects that the value has changed. This double notification could probably be considered a bug, since the latter notification should render the former unnecessary, and I'd consider filing a radar report on it.
Unfortunately, I can't see any way to disable this behavior. I can think of a workaround, but it's extremely hacky, kludgey, ugly, and I probably wouldn't actually do it unless the need is absolutely dire. But here it is:
private var kvoContext = 0
private let ignoreKVOKey = "com.charlessoft.example.IgnoreKVO"
// If this can be called from a thread other than the main thread,
// then you will need to take measures to protect it against race conditions
private var shouldIgnoreKVO = false
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &self.kvoContext { // always, always use a context pointer
if !shouldIgnoreKVO { // if this is a notification we don't want, ignore it
print("in observeValue keyPath: \(String(describing: keyPath)) value: \(UserDefaults.standard.integer(forKey: "testKey"))");
}
} else {
// call super if context pointer doesn't match ours
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
#IBAction func click(_ sender: NSButton) {
// we don't need this notification, since we'll get the later one
// resulting from the defaults having changed
self.shouldIgnoreKVO = true
defer { self.shouldIgnoreKVO = false }
UserDefaults.standard.set(arc4random(), forKey: "testKey");
}
Again, it's ugly, it's hacky, I probably wouldn't actually do it. But there it is.
Im a newbie in swift, please bear with me.
I have button-A that when clicked show a popover, the popover has a text field and a confirm button. when the confirm is clicked, any value on the text field will be used to change the button-A title.
My question is, how can we monitor if the button title was changed? Obviously We can see it visually but my goal is to do it programatically.
thoughts?
An example might help a little here. If a button name myButton I can observe those attributes with:
let options = NSKeyValueObservingOptions([.New, .Old, .Initial, .Prior])
self.addObserver(self, forKeyPath: "myButton.titleLabel.text", options: options, context: nil)
// Changes to these properties will trigger a call to:
override func observeValueForKeyPath(keyPath: String!,
ofObject object: AnyObject!,
change: NSDictionary!,
context: CMutableVoidPointer) {
println("CHANGE OBSERVED: \(change)")
}