I want to present the blue dot on the map that represents the user's location.
I've tried to do it like that:
override func viewWillAppear(animated: Bool) {
self.mapView.addObserver(self, forKeyPath: "myLocation", options: NSKeyValueObservingOptions.New, context: nil)
}
deinit {
self.mapView.removeObserver(self, forKeyPath: "myLocation")
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "myLocation" {
self.mapView.animateToLocation((object?.myLocation!!.coordinate)!)
self.mapView.animateToZoom(17)
}
}
but observeValueForKeyPath(keyPath: ofObject: change: context:) doesn't called and I can't understand why.
Thank you very much!
You can do this with following line of code. This will bring up the google's default blue dot on users current location.
self.mapView.myLocationEnabled = true
Related
I try to observe a property in a view controller, for example, isBeingDimissed property.. But It doesnt seem to work... Only when I set the options to .initial do I see that it works.
But I wanna observe new values.. Am I missing anything?
class ViewController: UIViewController {
var firstViewController = FirstViewController.init()
override func viewDidLoad() {
super.viewDidLoad()
firstViewController.addObserver(self, forKeyPath: #keyPath(UIViewController.isBeingPresented), options: .new, context: &myContext)
}
#IBAction func tapButton(_ sender: Any) {
present(firstViewController, animated: true, completion: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("let me see the change:", keyPath)
}
}
I have an ImageView called - (woowwww): ImageView
#IBOutlet weak var ImageView: UIImageView!
... and I'd like to fire an event every time the transform-property of the ImageView changed.
An event should get called every time the ImageView get's rotated by maybe something like this:
self.ImageView.transform = CGAffineTransform(rotationAngle: CGFloat(10))
To achieve this I tried to use some kind of KVO but obviously it is not working as expected...
override func viewDidLoad() {
super.viewDidLoad()
self.ImageView.addObserver(self.ImageView.transform, forKeyPath: "test", options: .new, context: nil)
}
func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutableRawPointer) {
print("changed")
}
Any help would be very appreciated! Thanks.
Set "transform" in keyPath like below:
imgView.addObserver(self, forKeyPath: "transform", options: .new, context: nil)
then add below code:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? NSObject {
print("Changed \(newValue)")
}
Hope it will help you.
keyPath should be nameOfObject.property so if imageView name is dd to listen to transform it's should dd.transform
Try this
class ViewController: UIViewController {
#IBOutlet weak var dd: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.addObserver(self, forKeyPath: "dd.transform", options: .new, context: nil)
self.dd.transform = CGAffineTransform(rotationAngle: CGFloat(10))
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? NSObject {
print("Changed \(newValue)")
}
}}
When I try to observe the progress of a NSBundleResourceRequest, observeValue(forKeyPath: object: change: context:) is not called for the .new observing option. Therefore, the NSProgressIndicator isn't updated. Here is the setup and code:
Setup:
Xcode 8.3.1
Deployment Target iOS 10.3
Device: iPad 4
Resource tags (368 KB) are located located in Download Only On Demand and consist of thumbnails displayed in a UICollectionView. Thumbnail images are located in MyCollection.xcassets. All IBOutlets are connected.
Images are correctly displayed in the collection view, but progress bar remains at zero.
Code:
final class MyCollectionVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var myCollectionVCResourceRequest: NSBundleResourceRequest!
var myCollectionVCResourceRequestLoaded = false
static var myCollectionProgressObservingContext = UUID().uuidString
private let designThumbnailTags: Set<String> = ["Resource1", "Resource2", "Resource3"]
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadOnDemandResources()
}
func loadOnDemandResources() {
myCollectionVCResourceRequest = NSBundleResourceRequest(tags: designThumbnailTags)
myCollectionVCResourceRequest.progress.addObserver(self, forKeyPath: "fractionCompleted", options: [.new, .initial], context: &MyCollectionVC.myCollectionProgressObservingContext)
myCollectionVCResourceRequest.beginAccessingResources(completionHandler: { (error) in
print("Complete: \(self.myCollectionVCResourceRequest.progress.fractionCompleted)") // Prints Complete: 0.0
self.myCollectionVCResourceRequest.progress.removeObserver(self, forKeyPath: "fractionCompleted", context: &MyCollectionVC.myCollectionProgressObservingContext)
OperationQueue.main.addOperation({
guard error == nil else { self.handleOnDemandResourceError(error! as NSError); return }
self.myCollectionVCResourceRequestLoaded = true
self.updateViewsForOnDemandResourceAvailability()
self.fetchDesignThumbnailsWithOnDemandResourceTags(self.myCollectionVCResourceRequest) // Correctly creates Core Data Instances
})
})
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &MyCollectionVC.myCollectionProgressObservingContext {
OperationQueue.main.addOperation({
let progressObject = object as! Progress
self.progressView.progress = Float(progressObject.fractionCompleted)
print(Float(progressObject.fractionCompleted)) // Prints 0.0 as a result of including the .initial option
self.progressDetailLabel.text = progressObject.localizedDescription
})
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
}
The following code is crashing at
currentCellRect = tableView.rectForRowAtIndexPath(indexPaths[0])
But only sometimes.
public func showCellScrollCount(animated:Bool) {
self.tableView.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: nil)
self.tableView.addObserver(self, forKeyPath: "dragging", options: NSKeyValueObservingOptions.New, context: nil)
}
override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
switch (keyPath, object) {
case (.Some("contentOffset"), _):
self.updateScrollPosition()
default:
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
func updateScrollPosition() {
let indexPaths = tableView.indexPathsForVisibleRows
var currentCellRect:CGRect?
if let indexPaths = indexPaths {
if indexPaths.count > 0 {
currentCellRect = tableView.rectForRowAtIndexPath(indexPaths[0])
scrollCountView.currentScrollCountNum = indexPaths[0].row
}
}
}
It crashes with "BAD_ACCESS". Does anyone have any idea why?
...
EDIT: Is it possible it's happening because I'm calling tableView.reloadData() right before I add observers, and the call isn't finished yet?
Updated
Your code works fine since I added it to my tableView controller and called showCellScrollCount func once. Where you call showCellScrollCount, do you call it multiple times? It can be problem if so.
Update 3
here is the problem:
public var totalScrollCountNum = 0 {
didSet {
scrollCountView.totalScrollCountNum = totalScrollCountNum
showCellScrollCount(false)
}
}
move showCellScrollCount(false) to initializers
I want to remove an observer after it run or when the view dissapeared. Here is the code but sometimes the observer was already removed when i want to remove it again. How to check if it is still registered?
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
if(!didOnce){
if(keyPath == "myLocation"){
location = mapView.myLocation.coordinate;
self.mapView.animateToLocation(self.location!);
self.mapView.animateToZoom(15);
didOnce = true;
self.mapView.removeObserver(self, forKeyPath: "myLocation");
}
}
}
override func viewDidAppear(animated: Bool) {
didOnce = false;
}
override func viewWillDisappear(animated: Bool) {
if(!didOnce){
self.mapView.removeObserver(self, forKeyPath: "myLocation");
didOnce = true;
}
}
You're on the right track. Add an isObserving property to your class. Set it to true when you start observing, and set it to false when you stop observing. In all cases check the flag before starting/stopping observing to make sure you are not already in that state.
You can also add a willSet method to the property and have that code start/stop observing when the property changes states.
Main reason: addObserver() is called 1 time (at viewDidLoad or init), but removeObserver() can be called 2 times or more (base on the times viewWillDisappear() was called).
To resolve: move addObserver() to viewWillAppear():
private var didOnce = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.mapView.addObserver(self, forKeyPath: "myLocation", options: .new, context: nil)
}
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
if(!didOnce){
if(keyPath == "myLocation"){
location = mapView.myLocation.coordinate;
self.mapView.animateToLocation(self.location!);
self.mapView.animateToZoom(15);
didOnce = true;
self.mapView.removeObserver(self, forKeyPath: "myLocation");
}
}
}
override func viewWillDisappear(animated: Bool) {
if(!didOnce){
self.mapView.removeObserver(self, forKeyPath: "myLocation");
didOnce = true;
}
}