I have referred the Apple's Swift Programming Language book, and it is of no help.
var fh = NSFileHandle.fileHandleWithStandardInput()
if let data = fh.availableData
{
var str = NSString(data: data, encoding: NSUTF8StringEncoding)
}
There is more to it than that. Typically in iOS development, you'll have a UITextView become first responder. A responder is an object (event handling object) that can respond to events and handle them. Once you make a UI element become first responder, you can accomplish what you want. From there, the keyboard appears and the user enters something.
Once that's done, you can resign the first responder and look at the text and use it however you want. Some rough code for this process looks like this:
//Create a label
let tv = UITextView(frame: CGRectMake(0, 0, 200, 100))
self.view.addSubView(tv)
//Tell iOS we want this to handle text input
tv.becomeFirstResponder()
//User enters text, tell iOS we're done handling text input events and print input
tv.resignFirstResponder()
println(tv.text)
A good resource for input in iOS: User Input in iOS
Related
I work on an iOS app that displays images that often contain text, and I'm adding support for ImageAnalysisInteraction as described in this WWDC 2022 session. I have gotten as far as making the interaction show up and being able to select text and get the system selection menu, and even add my own action to the menu via the buildMenuWithBuilder API. But what I really want to do with my custom action is get the selected text and do a custom lookup-like thing to check the text against other content in my app.
So how do I get the selected text from an ImageAnalysisInteraction on a UIImageView? The docs show methods to check if there is selected text, but I want to know what the text is.
I was trying to solve the same problem. However, there doesn't currently seem to be any straightforward way to get selected text from ImageAnalysisInteraction. The closest thing seems to be the ImageAnalysis.transcript property, but it contains all the OCR text, not just what the user selected.
My solution was to capture the text whenever the user taps on the copy button on the selection menu. You can do this by observing clipboard changes, which allows you to copy the selected text from the clipboard whenever a change is detected.
See:
Get notified on clipboard change in swift
How to copy text to clipboard/pasteboard with Swift
Hope this help you
// Step -1
import Vision
// Step -2
// converting image into CGImage
guard let cgImage = imageWithText.image?.cgImage else {return}
// Step -3
// creating request with cgImage
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
// Step -4
let request = VNRecognizeTextRequest { request, error in
guard let observations = request.results as [VNRecognizedTextObservation],
error == nil else {return}
let text = observations.compactMap({
$0.topCandidates(1).first?.string
}).joined(separator: ", ")
print(text) // text we get from image
}
// step -5
request.recognitionLevel = VNRequestTextRecognitionLevel
try handler.perform([request])
For Reference and more details
Currently I'm developing an email app and want all links with mailto scheme to be opened via my app, not default Apple's Mail app.
For instance, I have a link like this one
<a href="mailto:email#example.com\>mailto_test</a>
in UIWebView or UITextView (doesn't matter which one, they have similar behavior).
When I longpress this link iOS will show UIAlertController with 3 options:
The first one option, "New Message", will open default Mail app. So my question is how to override this behavior? How can i force this option to launch my own email app?
For those who think it is impossible - take a look at iOS Gmail app. Gmail devs have implemented what I'm asking about, but I don't understand how.
In a text view, link behavior is completely up to you. Give the text view a delegate and implement textView(_:shouldInteractWith:in:interaction:). A long press is the .presentActions interaction. Return false and substitute your own response. You can put up your own .actionSheet alert that looks just like the default one, but does what you want it to.
The solution is to change the default click action of the mail link to the way you want.
Make a UITextView example:
Suppose we have UITextView textView, its attributeString is
<a href="mailto:email#example.com\>mailto_test</a>
and its documentType is html. The code is below:
let textView = UITextView(frame: view.bounds)
textView.frame.origin.y += 100
let attrStr = try! NSAttributedString(
data: "mailto_test".data(using: .utf8, allowLossyConversion: true)!,
options:[.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil)
textView.attributedText = attrStr
view.addSubview(textView)
This the default effect that after pressed the mailto_test text in the screen the native mail app functions waked up. So we add a delegate to the textView to modify the click action.
textView.isEditable = false
textView.dataDetectorTypes = .link
textView.delegate = self
Here is the delegate function to control the specific click action:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
print(URL)
return false
}
Whenever you pressed the mail link, the functions invoked without calling the native mail app. And the URL is just the mail url.
You are looking for something like this, right? Where you can open your app from anywhere you click email URL.
I can't find the exact answer right now, but you want to add your app as a URL Scheme (Apple documentation)
Edit: more apple documentation
How can I get the console logs with all the print/Nslog contents and display it on a textview? Thank you very much for your answer.
To accomplish this I modified the OutputListener Class described in this article titled "Intercepting stdout in Swift" by phatblat:
func captureStandardOutputAndRouteToTextView() {
outputPipe = Pipe()
// Intercept STDOUT with outputPipe
dup2(self.outputPipe.fileHandleForWriting.fileDescriptor, FileHandle.standardOutput.fileDescriptor)
outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: outputPipe.fileHandleForReading , queue: nil) {
notification in
let output = self.outputPipe.fileHandleForReading.availableData
let outputString = String(data: output, encoding: String.Encoding.utf8) ?? ""
DispatchQueue.main.async(execute: {
let previousOutput = self.outputText.string
let nextOutput = previousOutput + outputString
self.outputText.string = nextOutput
let range = NSRange(location:nextOutput.count,length:0)
self.outputText.scrollRangeToVisible(range)
})
self.outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
}
}
}
If you do not want to change existing code, you can;
1 - redirect the output of print to a known file.
see instructions here; How to redirect the nslog output to file instead of console ( answer 4, redirecting)
2 - monitor the file for changes and read them in to display in your textView.
You cannot do that.
You can use some logger, witch allow you to add custom log destination.
You will have to change all print/NSLog calls to e.g. Log.verbose(message).
I'm using SwiftyBeaver. It allows you to define your custom destination. You can later read it and present in some text field.
You can totally do that! Check this out: https://stackoverflow.com/a/13303081/1491675
Basically you create an output file and pipe the stderr output to that file. Then to display in your textView, just read the file and populate your textView.
I'm just starting developing apps with Swift 2.0, and as I'm working having problem with initiating a variable with the value of a text field in my app.
this is the function I'm having problems with. It's called when a button under the text field is pressed as submit.
#IBAction func checkName(sender: AnyObject) {
guard let name : String = nameField.text else { print("Name not valid.");return}
let checker = NameChecker()
let result = checker.nameChecker(name)
print(result)
}
this only thing this code returns on the XCode shell is "lldb". I also tried to use the debugger to figure out where I was messing up but unfortunately I found out that was harder than expected and I wasn't able to.
If you have any idea why my code is only returning "lldb" I would really appreciate is you could let me know since I've been experiencing this error quite often lately.
I'm trying to find several different data types including Dates, Addresses, Phone numbers, and Links. I'm already able to find them but I want to be able to format them by underlining and changing their color. This is my code so far.
func detectData() {
let text = self.textView.text
let types: NSTextCheckingType = .Date | .Address | .PhoneNumber | .Link
var error: NSError?
let detector = NSDataDetector(types: types.rawValue, error: &error)
var dataMatches: NSArray = [detector!.matchesInString(text, options: nil, range: NSMakeRange(0, (text as NSString).length))]
for match in dataMatches {
I was thinking I should first get each result out of the loop then
1) turn them into strings 2)format them.
First question. How will I put my formatted string back into my UITextView at the same place?
Second question. I'm thinking about creating a switch like so
switch match {
case match == NSTextCheckingType.date
but now that I have a specific type of NSTextCheckingType, what do I have to do to make them have the functionality I want? (e.g. call a phone number, open up maps for an address, create a event for a date)
To do what Notes does you just need to set the dataDetectorTypes property on your text view. That's all! No NSDataDetector involved.