I am using Here Maps SDK in my project in Swift 3 (in Xcode 8 for iOS 10) to grab the currentPosition from NMAPositioningManager. However, while isActive is true for the NMAPositioningManager, the currentPosition is always nil. I have a valid position and valid credentials H(ERE_MAPS_APPID, HERE_MAPS_APP_CODE, and HERE_MAPS_LICENSE_KEY).
I checked the SDKDemo with Xcode 8 for iOS 10, which runs fine, but their code is in Objective-C. Any comment would be appreciated.
if let posMan : NMAPositioningManager = NMAPositioningManager.shared() {
if let currPos = posMan.currentPosition{
if let geoCoordCenter = currPos.coordinates {
self.mapView.setGeoCenter(geoCoordCenter, with: NMAMapAnimation.none)
}
}
}
Make sure positioning is started (I guess you did, but it's not shown in your snipped, so pasting it here again for reference):
NMAPositioningManager.shared().startPositioning()
Then normally it takes some time till your position is available, so you can't query dirctly PositionManager. I suggest to register for the position update callbacks:
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.positionDidUpdate), name: NSNotification.Name.NMAPositioningManagerDidUpdatePosition, object: NMAPositioningManager.shared())
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didLosePosition), name: NSNotification.Name.NMAPositioningManagerDidLosePosition, object: NMAPositioningManager.shared())
Then do in the callback with the position whatever you want:
func positionDidUpdate(){
if let p = NMAPositioningManager.shared().currentPosition {
mapView.setGeoCenter(p.coordinates, with: NMAMapAnimation.bow)
}
}
func didLosePosition(){
print("Position lost")
}
Let me know if it's still not working for you like this, and I'll add more complete code.
Related
I have multiple keyboards in my Xcode iOS Simulator. I'm running Swift (I need the code to work in Swift), and when they keyboard input type is changed in my app (e.g. from English to Spanish), I want to know which language it has been changed to.
I have a function in my ViewDidLoad:
NotificationCenter.default.addObserver(self,
selector: #selector(changeInputMode(_:)),
name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
and this function that supports it.
#objc func changeInputMode(_ notification: Notification)
{
let inputMethod = UITextInputMode.activeInputModes.description
print("keyboard changed to \(inputMethod.description)")
}
The inputMethod description prints out this for me:
[<UIKeyboardInputMode: 0x6000027a28a0>, <UIKeyboardInputMode: 0x6000027ab2f0>, <UIKeyboardInputMode: 0x6000027bc9b0>, <UIKeyboardInputMode: 0x6000027bca50>, <UIKeyboardInputMode: 0x6000027b8ff0>, <UIKeyboardInputMode: 0x6000027b9090>]
I would like to get the language in simpler terms, such as "english" or "en" or something like that. How can this be achieved?
I also tried the following:
let language = UITextInputMode.currentInputMode()?.primaryLanguage
print(language)
but I got an error:
'currentInputMode()' is unavailable in iOS: APIs deprecated as of iOS 7 and earlier are unavailable in Swift
Thanks for your help in advance.
Given a UIViewController, I would like to receive text input only from the external keyboard. Think UIKeyCommand but for any character (not just 'modified' ones).
However, when I try to implement that using UIKeyInput, it seems that iOS desperately wants to display a keyboard if there is no external one connected.
Is there any way to circumvent that? Specifically, to have the options to receive keystrokes from the keyboard if, and only if, one is connected?
After fiddling with a iPad for an hour, I finally have a good solution for this in swift. The other methods are weak or use 3rd party software. The reason why UIKeyboardWillShowNotification is getting fired even when an external keyboard is being used for an iPad is the shortcut bar existing. In order to disable the shortcut bar, do this:
let item : UITextInputAssistantItem = textField.inputAssistantItem
item.leadingBarButtonGroups = []
item.trailingBarButtonGroups = []
This covers most cases of what you need, but UIKeyboardWillShowNotification can still be fired if someone plugs their keyboard in at certain points of use. If you have the screen adjust, you can't afford any case for the user to experience this. Plus, you might want the shortcut bar for some reason. Regardless of what your desires are, this covers all cases of an external keyboard being used:
Add to viewDidAppear
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LoginViewController.keyboardWillShow), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LoginViewController.keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)
whenever you leave the view add this to anything that makes you leave
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
also add it to the deinit{} method to be thourough.
Now use these functions:
func keyboardWillShow(notification: NSNotification) {
// This code is an alternate way of checking for keyboard
var userInfo: [NSObject: AnyObject] = notification.userInfo!
let firstFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let secondFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue
let firstRect = firstFrame.CGRectValue()
let secondRect = secondFrame.CGRectValue()
let diff = abs(firstRect.origin.y - secondRect.origin.y)
let isFirstBigger = firstRect.origin.y > secondRect.origin.y
if firstRect != secondRect && diff != 55 {
if !isFirstBigger {
//animateViewToDefaultPosition()
} else {
//animateViewToPositionWhenKeyboardActive()
}
}
}
func keyboardWillHide() {
//animateViewToDefaultPosition()
}
The 55 is the height of the shortcut bar. You can remove it's functionality if you don't have one. The !isFirstBigger is used to check for when they unhook the keyboard and hook it back in during text field editing. It is also important that diff != 55 during that check because with a shortcut bar this would be the case when you did not want to animate the screen.
This is by far the best method I have seen after scouring Stack Overflow. If anyone finds a bug in the functionality, let me know, but I am confident it will take care of the pesky shortcut bar external keyboard issues. I hope this helps everyone else out there confused by all this!
I am migrating an application from the deprecated Address Book Framework to the new Contacts Framework. The application utilizes ABAddressBookRegisterExternalChangeCallback to be notified when another application changes a contact.
I am unable to find equivalent functionality in the Contacts Framework. Apple documentation says to use the default notification center with the CNContactStoreDidChangeNotification notification:
The notification posted when changes occur in another CNContactStore.
Taking Apple's advice, my code looks like this:
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "contactsChanged:",
name: CNContactStoreDidChangeNotification,
object: nil)
However, I have found two problems with this approach:
I am notified for all changes, including those made by my own application.
Notifications are spurious - I receive many notifications for a single change.
If I log the debug description of the notification when the change was made within my app, I get something like this:
NSConcreteNotification 0x7d3370e0 {name = CNContactStoreDidChangeNotification; userInfo = {
CNNotificationOriginationExternally = 1;
CNNotificationSourcesKey = (
);
}}
And if the changes are made externally:
NSConcreteNotification 0x7bf7a690 {name = CNContactStoreDidChangeNotification; userInfo = {
CNNotificationOriginationExternally = 1;
CNNotificationSourcesKey = (
);
}}
As you can see, nothing obvious with which to distinguish them.
Can anyone tell me how to get the same behavior from the Contacts Framework as one can get from ABAddressBookRegisterExternalChangeCallback?
First, I'd recommend filing a bug with Apple about the lack of a way to identify internal vs external changes in the API.
As a possible workaround, you could see if unregistering your observer before making a change and re-registering immediately afterward ensures that you miss all of your change notifications and still get all the external ones:
class ContactsThingy {
var observer: NSObjectProtocol?
let contacts = CNContactStore()
func contactStoreDidChange(notification: NSNotification) {
NSLog("%#", notification)
}
func registerObserver() {
let center = NSNotificationCenter.defaultCenter()
observer = center.addObserverForName(CNContactStoreDidChangeNotification, object: nil, queue: NSOperationQueue.currentQueue(), usingBlock: contactStoreDidChange)
}
func unregisterObserver() {
guard let myObserver = observer else { return }
let center = NSNotificationCenter.defaultCenter()
center.removeObserver(myObserver)
}
func changeContacts(request: CNSaveRequest) {
unregisterObserver() // stop watching for changes
defer { registerObserver() } // start watching again after this change even if error
try! contacts.executeSaveRequest(request)
}
}
I thought I have tried everything and read every possible articles in this forum. But nothing seems to work. Here is some code snippet and some settings:
On Extension side:
let thisDefaults = NSUserDefaults(suiteName: "group.request.com")
thisDefaults?.setObject("Hello", forKey: "prevWord")
thisDefaults?.setObject("World", forKey: "word")
let success = thisDefaults?.Synchronize()
NSNotificationCenter.defaultCenter().postNotificationName("ExtensionRequestChanges", object: nil)
On Containingg app side:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("DidReceiveRequest:", name: "ExtensionRequestChanges",
object: nil)
func DidReceiveRequest(notification: NSNotification) {
// Read defaults
let thisDefaults = NSUserDefaults(suiteName: "group.request.com")
let word = thisDefaults?.stringForKey("word")
let prevWord = thisDefaults?.stringForKey("prevWord")
...
}
On the project settings:
. registered "group.request.com" app group to both the extension and containing app
. set "RequestOpenAccess" in NSExtensionAttributes to YES
But my DidReceiveRequest function never seemed to get called! Why???
Please help.
NSNotificationCenter only works in the process it's running in. Your keyboard extension and container app are separate processes. To post interprocess notifications, you should investigate the CFNotificationCenterGetDarwinNotifyCenterAPI call, which returns a Core Foundation notification center that can post notifications between processes, or other forms of interprocess communication.
I already found a lot of approaches for this but no working solution. Here's what I tried and didn't work.
(1) Simply calling primaryLanguage()
UITextInputMode().primaryLanguage
→ always returns nil :-/
(2) Subscribing to UITextInputCurrentInputModeDidChangeNotification notifications
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "changeInputMode:", name: UITextInputCurrentInputModeDidChangeNotification, object: nil)
}
func changeInputMode(sender : NSNotification) {
...?!
}
The notification is getting triggered but it is unclear how I can extract the current language information from the notification.
(3) Using activeInputModes()
let localeIdentifier = UITextInputMode.activeInputModes().first as? UITextInputMode
var locale:NSLocale = NSLocale(localeIdentifier: localeIdentifier.primaryLanguage!)
println("Input Mode Language \(localeIdentifier.primaryLanguage!)")
This always provides the same array of all available keyboards, no information on the actually active one.
How do I get the NSLocale of the currently active keyboard?
You can access the primaryLanguage from every textfield by accessing the textfields textInputMode like that:
var language = textfield.textInputMode?.primaryLanguage