NSTextViewDelegate crashing - swift

I have a small project with an NSTextview and a delegate that catches changes in text, as below. The object EditViewHandler works fine when it's a global but crashes when text is added to the view if it's local to viewDidLoad(). So this is obviously the wrong way to do it but what would be the correct way of doing this:
#IBOutlet var EditPaneOutlet: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
let e = EditViewHandler( EditPaneOutlet: EditPaneOutlet )
}
class EditViewHandler : NSObject, NSTextViewDelegate {
var EditPaneOutlet: NSTextView! = nil
init( EditPaneOutlet: NSTextView ) {
super.init()
self.EditPaneOutlet = EditPaneOutlet
self.EditPaneOutlet!.delegate = self
}
func textDidChange(_ notification: Notification) {
print( "text changed")
}
}

Related

Problem saving text from UITextView into Realm (Swift 5)

Trying to save the user's textView.text into Realm. Figured if I call my save function into the textFieldDidEndEditing function, it would trigger my Realm database to save it. Function runs ok (prints "Saved Successfully" when I end editing), but when I close out and come back, none of the data is there.
import UIKit
import RealmSwift
class NoteViewController: UIViewController, UITextViewDelegate {
var textView = UITextView()
var notes: Results<Notes>?
let realm = try! Realm()
var selectedNote: Menu? {
didSet {
loadNotes()
}
}
#IBOutlet weak var theTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
loadNotes()
self.textView.delegate = self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
override func viewDidDisappear(_ animated: Bool) {
saveNote()
}
func textViewDidBeginEditing(_ textView: UITextView) {
}
func textViewDidEndEditing(_ textView: UITextView) {
saveNote()
}
//MARK: - Data Manipulation
func loadNotes() {
notes = realm.objects(Notes.self)
textView.reloadInputViews()
}
func saveNote() {
if let currentNote = self.selectedNote {
do {
try self.realm.write {
let newNote = Notes()
newNote.body = theTextView.text!
newNote.dateCreated = Date()
currentNote.notes.append(newNote)
print("Saved successfully")
}
} catch {
print("Error saving note body, with \(error)")
}
}
}
}
Realm File:
class Notes: Object {
#objc dynamic var body: String = ""
#objc dynamic var dateCreated: Date?
var parent = LinkingObjects(fromType: Menu.self, property: "notes")
}
Menu Realm File:
class Menu: Object {
#objc dynamic var name: String = ""
#objc dynamic var preview: String = ""
let notes = List<Notes>()
}
'''
It looks like you are using a storyboard to create your layout.
Get rid of var textView = UITextView() and textView.reloadInputViews() then.
Replace self.textView.delegate = self with theTextView.delegate = self in viewDidLoad().
To check the content of theTextView modify your print statement:
print("Saved successfully: \(theTextView.text!)")
If there is no text printed right after "Saved successfully: " then check Interface builder for theTextView: verify the outlet of theTextView and that this is actually the UITextView you are using (since your app does print something it looks like it is hooked up somehow because otherwise it would crash in newNote.body = theTextView.text!).
I think you also forgot to actually initialise theTextView with notes.body.
Try to modify loadNotes() like this:
func loadNotes() {
notes = realm.objects(Notes.self)
theTextView.text = notes.body
}

Parse PFUser not registering subclass

I am trying to use Parse PFUser in a software for OSX desktop. When I try to use it PFUser.query() it gives a message: Failed to set (contentViewController) user defined inspected property on (NSWindow): The class PFUser must be registered with registerSubclass before using Parse.
It is happening without registering the class.
I tried it registering the class this way: PFUser.registerSubclass() but it still doesn't work.
I will use the default PFUser without adding any fields to it, so I don't need to create a custom class to be my PFUser.
I tried to use PFUser.enableAutomaticUser() without success
Code below:
AppDelegate.swift
import Cocoa
import Parse
import Bolts
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let APP_ID = "app_id"
let CLIENT_KEY = "client_key"
let SERVER = "https://parseserver.com/"
func applicationDidFinishLaunching(_ aNotification: Notification) {
PFUser.registerSubclass()
let configuracaoParse = ParseClientConfiguration {
$0.applicationId = self.APP_ID
$0.clientKey = self.CLIENT_KEY
$0.server = self.SERVER
}
Parse.initialize(with: configuracaoParse)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
ViewController.swift
import Cocoa
import Parse
class ViewController: NSViewController {
#IBOutlet weak var emailTextField: NSTextField!
#IBOutlet weak var senhaSecureTextField: NSSecureTextField!
override func viewDidLoad() {
super.viewDidLoad()
contaUsuarios()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func entrarButtonClicked(_ sender: NSButton) {
}
func contaUsuarios() {
let query = PFUser.query()
query?.countObjectsInBackground(block: {
(count, error) -> Void in
let numeroUsers = Int(UInt32(count))
if numeroUsers > 0 {
}
print(numeroUsers)
})
}
}
Reading some content on the internet I discovered that in OSX the ViewController is launched before the AppDelegate finishes loading, so I initialized the Parse connection and subclassing in the ViewController's viewDidLoad instead of AppDelegate and it is working just fine.

Swift function textfield got focus OSX

Currently I am having multiple textfields in a view. If the user taps at one of them there should be a function responding to the event. Is there a way on how to do react (if a textfield got the focus)? I tried it with the NSTextFieldDelegate method but there is no appropriate function for this event.
This is how my code looks at the moment:
class ViewController: NSViewController, NSTextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let textField = NSTextField(frame: CGRectMake(10, 10, 37, 17))
textField.stringValue = "Label"
textField.bordered = false
textField.backgroundColor = NSColor.controlColor()
view.addSubview(textField)
textField.delegate = self
let textField2 = NSTextField(frame: CGRectMake(30, 30, 37, 17))
textField2.stringValue = "Label"
textField2.bordered = false
textField2.backgroundColor = NSColor.controlColor()
view.addSubview(textField2)
textField2.delegate = self
}
func control(control: NSControl, textShouldBeginEditing fieldEditor: NSText) -> Bool {
print("working") // this only works if the user enters a charakter
return true
}
}
The textShouldBeginEditing function only handles the event if the user tries to enter a character but this isn't what I want. It has to handle the event if he clicks on the textfield.
Any ideas, thanks a lot?
Edit
func myAction(sender: NSView)
{
print("aktuell: \(sender)")
currentObject = sender
}
This is the function I want to call.
1) Create a subclass of NSTextField.
import Cocoa
class MyTextField: NSTextField {
override func mouseDown(theEvent:NSEvent) {
let viewController:ViewController = ViewController()
viewController.textFieldClicked()
}
}
2) With Interface building, select the text field you want to have a focus on. Navigate to Custom Class on the right pane. Then set the class of the text field to the one you have just created.
3) The following is an example for ViewController.
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
func textFieldClicked() -> Void {
print("You've clicked on me!")
}
}
4) Adding text fields programmatically...
import Cocoa
class ViewController: NSViewController {
let myField:MyTextField = MyTextField()
override func viewDidLoad() {
super.viewDidLoad()
//let myField:MyTextField = MyTextField()
myField.setFrameOrigin(NSMakePoint(20,70))
myField.setFrameSize(NSMakeSize(120,22))
let textField:NSTextField = NSTextField()
textField.setFrameOrigin(NSMakePoint(20,40))
textField.setFrameSize(NSMakeSize(120,22))
self.view.addSubview(myField)
self.view.addSubview(textField)
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
func textFieldClicked() -> Void {
print("You've clicked on me!")
}
}
I know it’s been answered some while ago but I did eventually find this solution for macOS in Swift 3 (it doesn’t work for Swift 4 unfortunately) which notifies when a textfield is clicked inside (and for each key stroke).
Add this delegate to your class:-
NSTextFieldDelegate
In viewDidLoad() add these:-
imputTextField.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: Notification.Name.NSTextViewDidChangeSelection, object: nil)
Then add this function:-
func textDidChange(_ notification: Notification) {
print("Its come here textDidChange")
guard (notification.object as? NSTextView) != nil else { return }
let numberOfCharatersInTextfield: Int = textFieldCell.accessibilityNumberOfCharacters()
print("numberOfCharatersInTextfield = \(numberOfCharatersInTextfield)")
}
Hope this helps others.

Changing the view color when comparing values

I created a view to use as background and I would like to change its color when label text is greater or less than variable number. The script is okay but the color is not changing.
Thanks in advance.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var localName: UITextField!
#IBOutlet weak var localNameLabel: UILabel!
#IBOutlet weak var localTemp: UILabel!
#IBAction func getData(sender: AnyObject) {
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=" + localName.text! + "")
}
#IBOutlet weak var fundo: UIView!
override func viewDidLoad() {
super.viewDidLoad()
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=London")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getWeatherData(urlString: String){
let url = NSURL (string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.setLabels(data!)
})
}
task.resume()
}
func setLabels(weatherData: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(weatherData, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
print(json)
//localNameLabel.text = json[("name")] as? String
if let name = json[("name")] as? String {
localNameLabel.text = name
}
if let main = json[("main")] as? NSDictionary {
if let temp = main[("temp")] as? Double {
//convert kelvin to celsius
let ft = (temp - 273.15)
let myString = ft.description
localTemp.text = myString
self.changeColor()
}
}
} catch let error as NSError {
print(error)
}
var number : Float
func changeColor(){
number = 19.0
if(Float(localTemp.text!) < number){
fundo.backgroundColor = .blueColor()
}else{
fundo.backgroundColor = .orangeColor()
}
}
}
}
Edited to post the entire script
In your view controller you need to add UITextFieldDelegate which will allow you to access methods related to your text field. The top of your view controller should look like this:
class ViewController: UIViewController,UITextFieldDelegate //set delegate to class
You then need to set the delegate of your text field to self in viewDidLoad and add a target for when the text field changes:
override func viewDidLoad() {
super.viewDidLoad()
localTemp.delegate = self //set delegate to this vc
localTemp.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
You can then implement this method which will run on every key press and you need to call your changeColor() method as above:
func textFieldDidChange(textField: UITextField) {
self.changeColor()
}

PopUpPicker - does not conform to protocol

I am very new to Swift and programming in general.
I am trying to add a Pop Up Picker on a textfield and when the user selects the item from the picker, they can press OK with that item displayed in the textfield and the PopUp disappear.
I have successfully implemented this with a Pop Up Date Picker as I have used this from GutHub successfully. I thought it would be easy to mimic this code for my Pop Up Picker which has proven to be more difficult than expected.
I have a sepeate XIB file which holds the View with the Picker and OK Button. I then have 2 swift files one for the PopViewController and the other for the PopPicker.
Not even sure if this code is correct but the error I am getting is that my Picker does not conform to protocol. Code is below for both files.
PopEngineViewController
import UIKit
protocol EnginePickerViewControllerDelegate : class {
func enginePickerVCDismissed(string: UITextField?)
}
class PopEngineViewController: UIViewController {
#IBOutlet weak var container: UIView!
#IBOutlet weak var enginePicker: UIPickerView!
weak var delegate : EnginePickerViewControllerDelegate?
override convenience init() {
self.init(nibName: "PopEnginePicker", bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidDisappear(animated: Bool) {
self.delegate?.enginePickerVCDismissed(nil)
}
}
and PopEnginePicker
import UIKit
public class PopEnginePicker : NSObject, UIPopoverPresentationControllerDelegate, EnginePickerViewControllerDelegate {
public typealias PopEnginePickerCallback = (forTextField : UITextField)->()
var enginePickerVC : PopEngineViewController
var popover : UIPopoverPresentationController?
var textField : UITextField!
var dataChanged : PopEnginePickerCallback?
var presented = false
var offset : CGFloat = 8.0
public init(forTextField: UITextField) {
enginePickerVC = PopEngineViewController()
self.textField = forTextField
super.init()
}
public func pick(inViewController : UIViewController, dataChanged : PopEnginePickerCallback) {
if presented {
return // we are busy
}
enginePickerVC.delegate = self
enginePickerVC.modalPresentationStyle = UIModalPresentationStyle.Popover
enginePickerVC.preferredContentSize = CGSizeMake(500,208)
popover = enginePickerVC.popoverPresentationController
if let _popover = popover {
_popover.sourceView = textField
_popover.sourceRect = CGRectMake(self.offset,textField.bounds.size.height,0,0)
_popover.delegate = self
self.dataChanged = dataChanged
inViewController.presentViewController(enginePickerVC, animated: true, completion: nil)
presented = true
}
}
func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle {
return .None
}
}
Not even sure if I am going down the complete wrong path however I want it to look like the below as I have done with the date picker as it shows in the link below:
http://coding.tabasoft.it/ios/a-simple-ios8-popdatepicker/