Know when dictation has ended in a UITextView - ios

I'd like to know when dictation has end (ideally also when it started).
My UIViewController which includes the UITextView conforms to the UITextInputDelegate protocol.
To make it work I had to subscribe to the UITextInputCurrentInputModeDidChangeNotification
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "changeInputMode:", name: UITextInputCurrentInputModeDidChangeNotification, object: nil)
}
and add the delegate there (it didn't work simply adding it to the viewDidLoad())
func changeInputMode(sender : NSNotification) {
textView.inputDelegate = self
}
Starting and stopping dictation the UITextInput now correctly calls the required delegate methods:
func selectionWillChange(textInput: UITextInput){ }
func selectionDidChange(textInput: UITextInput){ }
func textWillChange(textInput: UITextInput){ }
func textDidChange(textInput: UITextInput){ }
However what doesn't get called is
func dictationRecordingDidEnd() {
println("UITextInput Dictation ended")
}
Why? How can I get notified/call a method on dictation having ended?

Okay, here's what worked for me not using the UITextInput protocol but the UITextInputCurrentInputModeDidChangeNotification instead.
func changeInputMode(sender : NSNotification) {
var primaryLanguage = textView.textInputMode?.primaryLanguage
if primaryLanguage != nil {
var activeLocale:NSLocale = NSLocale(localeIdentifier: primaryLanguage!)
if primaryLanguage == "dictation" {
// dictation started
} else {
// dictation ended
}
}
}

Related

I don't understand why my object doesn't receive notifications

I've create a custom class that looks like:
class FooDevice: Device {
private var controller:FooController?
private var device:Foo?
override init() {
super.init()
if super.authGranted {
NotificationCenter.default.addObserver(self, selector: #selector(self.discovered(_:)), name: NSNotification.Name(rawValue: FooDiscover), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.connected(_:)), name: NSNotification.Name(rawValue: FooConnected), object: nil)
}
}
#objc private func discovered(_ notification:Notification) {
DDLogVerbose("FOO - discovered - \(notification)")
super.scanner?.stopScanFor(._FOO)
// TODO: Call super.connector and connect
}
#objc private func connected(_ notification:Notification) {
DDLogVerbose("FOO - connected - \(notification)")
// Do more stuff after connect
}
func start() {
DDLogVerbose("FOO - startMeasurement()")
super.scanner?.scanFor(._FOO)
}
}
The super class looks like:
class Device: NSObject {
private let LICENSE = "my_license"
private var authenticator:SDKAuthenticator?
internal var scanner:SDKScanner?
internal var connector:SDKConnector?
internal var authGranted = false
override init() {
super.init()
authGranted = self.authRequest(LICENSE)
if authGranted {
scanner = SDKScanner.getInstance()
connector = SDKConnector.getInstance()
} else {
// TODO: Show error to user
}
}
private func authRequest(_ data:String) -> Bool {
// Do stuff using authenticator and authenticated, we can assume we return a true
return status // true
}
}
In my ViewController I make an instance of FooDevice and start the process. I'm doing with the following:
class MyViewController:UIViewController {
// A lot of properties
override viewDidLoad() {
// ViewDidLoad stuff
}
#IBAction func connectToDevice(_ sender: Any) {
// Here I instantiate the object and start the scanning
let myFooDevice = FooDevice()
myFooDevice.start()
}
}
In the console I could see how the scanner start and found the bluetooth device but the notification isn't captured and the log isn't printed. Also the notification names are right, I'm sure because the SDK return the strings.
I don't know what I'm missing. Hope you could throw some light to it.
Your problem is that ARC will cleanup your myFooDevice variable before any notification can reach it.
You better store it in a property:
class MyViewController:UIViewController {
var myFooDevice:FooDevice?
override viewDidLoad() {
// ViewDidLoad stuff
}
#IBAction func connectToDevice(_ sender: Any) {
// Here I instantiate the object and start the scanning
myFooDevice = FooDevice()
myFooDevice!.start()
}
}

Mysterious memory leak with UIActivity and UIActivityViewController

I'm running into what looks like a memory leak using Swift on iOS.
Here's a pared-down runnable example — you can tap the screen to show a share sheet, and BadActivity will leak every time.
import UIKit
class ViewController: UIViewController {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let activity = ShareController(activityItems: [""], applicationActivities: [BadActivity(), GoodActivity()])
self.showViewController(activity, sender: nil)
}
}
class ShareController: UIActivityViewController {
deinit { print("ShareController deinit.") }
}
class GoodActivity: UIActivity {
override func activityTitle() -> String { return "Good" }
deinit { print("Good deinit. This is printed.") }
}
class BadActivity: UIActivity {
override func activityTitle() -> String { return "Bad" }
deinit { print("Bad deinit. This is never printed.") }
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
return true
}
override func performActivity() {
self.activityDidFinish(true)
}
}
Regardless of whether you cancel the dialog or press export, BadActivity is instantiated but never deallocated – the console output is ShareController deinit. Good deinit.
If you make BadActivity.canPerformWithActivityItems return false instead of true, however, it deallocates normally.

Why I can't call a method stored in parent UIViewController from embedded UITableViewController?

I have a parent ui view controller and it has a method responsible for printing data to the console:
func printSomeData() {
print("printing some data")
}
It also has a container with embedded UITableViewController. The table itself has a pull to refresh functionality implemented and it prints the string when user pulls the table:
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
refreshControl.endRefreshing()
}
Now I want to call printsomeData from the refresh method.
This is what I try:
parent UIViewController:
class MainMenu: UIViewController, printing{
func printSomeData() {
print("some date")
}
}
embedded UITableViewController:
protocol printing{
func printSomeData()
}
class MainMenuTableViewController: UITableViewController {
var delegate: printing?
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
if let _ = delegate{
delegate?.printSomeData()
}
refreshControl.endRefreshing()
}
But now when I pull the table I only see Refreshing!!, there is no way I could see printing some data. What am I doing wrong?
Where are you assigning the delegate?
And write the optional method call as a single line
delegate?.printSomeData()
or like that:
if self.delegate != nil {
self.delegate!.printSomeData()
}
Inside MainMenu
override func viewDidLoad() {
super.viewDidLoad()
// tableViewController is placeholder for `MainMenuTableViewController` reference
tableViewController.delegate = self
}
If i have understand you correctly and the MainMenu has a ContainerView with MainMenuTableViewController than should this solve your problem:
class MainMenu: UIViewController, Printer {
func printSomeData() {
print("some date")
}
}
protocol Printer {
func printSomeData()
}
class MainMenuTableViewController: UITableViewController {
var printer: Printer? {
guard let printer = self.parentViewController as? Printer else {
return nil
}
return printer
}
func refresh(refreshControl: UIRefreshControl) {
print("Refreshing!!")
printer?.printSomeData()
refreshControl.endRefreshing()
}
}

Notify user reachability (Ashley Mills' Reachability)

I made an app, I want to add function that notify user when app's internet reachability is changed.
I use Ashley Mills' Reachability.swift file.
now I understand how it works, So I put code that when internet reachability is changed, it will print it's status in appDelegate.
However when I tried to put in function that alert user there isn't internet connection, It gets an error.
here is my code in app delegate.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var reachability : Reachability?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
do {
let reachability = try Reachability.reachabilityForInternetConnection()
self.reachability = reachability
} catch ReachabilityError.FailedToCreateWithAddress(let address) {
}
catch {}
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: ReachabilityChangedNotification, object: reachability)
do {
try reachability?.startNotifier()
} catch {}
return true
}
func reachabilityChanged(notification: NSNotification) {
let reachability = notification.object as! Reachability
if reachability.isReachable() {
print("reached")
} else {
print("not reached")
}
}
This works well.
However the code in Viewcontroller,
class ViewController: UIViewController {
var reachability : Reachability?
#IBOutlet weak var label: UILabel!
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "HeyUserInternetDoesntWork", name: ReachabilityChangedNotification, object: nil)
//get call from appDelegate Notification.
}
func HeyUserInternetDoesntWork() {
if reachability!.isReachable() {
print("notify User working")
} else {
print("Notify user not working")
}
}
unexpectedly found nil while unwrapping an Optional value
It gets this error.
I am going to put code for alerting user after it works.
Question here,
How Can I make it this work?
It doesn't have to be use that method, but I want to keep using NSNotification.
Actually I am a new guy for coding, So please explain details.
Where do you init reachability property? this variable is always nil.
In func HeyUserInternetDoesntWork you try to use reachability and of course it gets error. You need to init property like this:
private let reachability = Reachability.reachabilityForInternetConnection()
After use func HeyUserInternetDoesntWork with 'dynamic' keyword like this:
dynamic func HeyUserInternetDoesntWork() {
if reachability!.isReachable() {
print("notify User working")
} else {
print("Notify user not working")
}
}
Because NSNotificationCenter observer selector should be dynamic.

iOS Swift how to tell the UIView Controller that we received information via a NSURLProtocol object

I created a class that implements NSURLProtocol which will tells me about the UIWebView requests. I am looking to tell the UI that we hit a URL of interest and run code back on the ViewController to access the WebView.
I believe Protocols are the solution but cant seem to wrap my head around how to get this to work. Any suggestions and code example would be much appreciated. Here is what I've tried so far.
UI View Controller.swift
class WebViewController: UIViewController,WebAuthDelegate {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://example.com")
let request = NSURLRequest(URL: url!)
webView.loadRequest(request)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func onBackClick(sender: AnyObject) {
if(webView.canGoBack){
webView.goBack()
}
}
#IBAction func onFwdClick(sender: AnyObject) {
if(webView.canGoForward){
webView.goForward()
}
}
#IBAction func onRefresh(sender: AnyObject) {
webView.reload()
}
func getUserToken() {
print("RUN THIS AFTER I HIT URL IN URL PROTOCAL CLASS")
}
}
Here is my NSURLProtocol implemented class along with the attempted protocol(which please tell me if its the wrong approach)
class CUrlProtocol: NSURLProtocol {
//let delegate: WebAuthDelegate? = nil
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
print("URL = \(request.URL!.absoluteString)")
if request.URL!.absoluteString == "http://api-dev.site.com/token" {
//Tell the UI That we now have the info and we can access the UIWebView Object
}
return false
}
}
protocol WebAuthDelegate{
func getUserToken()
}
The best way to achieve this would probably be to post an NSNotification from your protocol when you match the URL.
In CUrlProtocol, when you find a match (notification name can be your choosing):
let notification:NSNotification = NSNotification(name: "MyURLMatchedNotification", object: nil)
NSNotificationCenter.defaultCenter().postNotification(notification)
In your WebViewController:
// During init (or viewDidAppear, if you only want to do it while its on screen)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getUserToken", name: "MyURLMatchedNotification", object: nil)
...
// During dealloc (or viewWillDisappear)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "MyURLMatchedNotification", object: nil)
You can also pass something with your notification, if you need information from that request. Just set the object parameter when you create your notification and change your getUserToken to accept a single parameter that has a type of NSNotification and access its object property.

Resources