I have a class, Listner:
class Listner {
typealias ListenerType = () -> ()
var listeners: [ListenerType] = []
init<V: UIControl>(view: V, event: UIControlEvents, listener: #escaping ListenerType) {
print("Init") // Prints
view.addTarget(self, action: #selector(actionEvent), for: event)
self.listeners.append(listener)
}
#objc private func actionEvent() {
print("EventChanged") // Does not print
self.listeners.forEach { (listner) in
listner()
}
}
}
that takes in a view that is a UIControl and adds a target to it. I know the target is added successfully because when I print view.allTargets I can see the just added target.
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
Listner(view: textField, event: .editingChanged) {
print("listen")
}
}
When I call the class like I did above and type in the textfield, actionEvent() is never called.
You need to make the Listner as a member variable so that it will not go out of scope after the viewDidLoad is called. If it's a member variable then it will be called when any editing is done to your control.
class ViewController : UIViewController {
#IBOutlet weak var textField: UITextField!
var listner : Listner!
override func viewDidLoad() {
super.viewDidLoad()
self.listner = Listner(view: textField, event: .allEditingEvents) {
print("listen")
}
}
}
Related
I'm having issues with passing a custom protocol (MainWindowControllerProtocol) to the EditorViewController from the MainWindowController, which is subclass of NSWindowController. Please help.
EditorViewController.swift
extension EditorViewController: MainWindowControllerProtocol {
func didOpenFile() {
print("TODO: Open File") // never called, but it should be
}
}
class EditorViewController: NSViewController {
// - IBOutlets
#IBOutlet weak var treeOutlineView: NSOutlineView!
#IBOutlet var codeTextView: NSTextView!
#IBOutlet weak var counterTextField: NSTextField!
#IBOutlet weak var languageTextField: NSTextField!
//public var editor = Editor()
//var rootNode: Node?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
//rootNode = Path(Path.userDownloads).node
// Issue is here
if let windowController = NSApplication.shared.mainWindow?.windowController as? MainWindowController {
windowController.delegate = self
}
else {
print("Doesnt work") // prints this
}
//treeOutlineView.reloadData()
}
}
MainWindowController
public protocol MainWindowControllerProtocol {
func didOpenFile()
}
class MainWindowController: NSWindowController {
var delegate: MainWindowControllerProtocol?
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
#IBAction func openFile(_ sender: Any) {
print("In here") // this is called?
delegate?.didOpenFile() // but this never is apparently
}
}
Maybe this topic should help.
This method might return nil if the application’s nib file hasn’t
finished loading, if the receiver is not active, or if the application
is hidden.
Have you checked if NSApplication.shared.mainWindow is nil or just NSApplication.shared.mainWindow?.windowController cannot be casted to your controller class ?
How use SFAuthorizationView in a swift project. I already tried by creating a bridging header and imported SecurityInterface/SFAuthorizationView.h . My code is given below.
My reference -https://github.com/dominikhofacker/SFAuthorizationView.
The Authorization View and lock icon appeared on my output screen. But when i click on the lock button nothing happens.
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var auth: SFAuthorizationView!
#IBOutlet weak var button: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var items = [ AuthorizationItem(name: kAuthorizationRuleIsAdmin, valueLength: 0, value: nil, flags: 0), ]
var rights = AuthorizationRights(count: UInt32(items.count), items: &items)
auth.setAuthorizationRights(&rights)
auth.setDelegate(self)
auth.updateStatus(nil)
button.isEnabled = isUnlocked()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func isUnlocked() -> Bool {
return auth.authorizationState() == SFAuthorizationViewUnlockedState;
}
override func authorizationViewDidAuthorize(_ view: SFAuthorizationView!) {
button.isEnabled = isUnlocked()
}
override func authorizationViewDidDeauthorize(_ view: SFAuthorizationView!) {
button.isEnabled = isUnlocked()
}
#IBAction func button(_ sender: Any) {
print("hihi")
}
}
Seems like you just forgot to disable sandbox mode at Capabilities tab of your project target
I'm very new to Swift MacOS programming and have been learning by writing small test applications.
The aim of this application is to enable the pushbutton when the 2nd textfield has the focus, and disable it when it is not focused.
I have found that by subclassing the NSTextField I can override becomeFirstResponder() however don't know how to set the button to be disabled from the subclass.
ViewController:
class ViewController: NSViewController {
#IBOutlet public weak var pushButton: NSButton!
#IBOutlet weak var textField3: NSTextField!
#IBOutlet weak var textField2: GSTextField!
#IBOutlet weak var textField1: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField2.delegate = self
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func chgButton(onoff: Bool){
pushButton.isEnabled = onoff
}
}
// When the field completes editing make the pushbutton disabled.
extension ViewController: NSTextFieldDelegate {
override func controlTextDidEndEditing(_ obj: Notification) {
print("did end")
chgButton(onoff: false)
}
}
GSTextField.Swift
class GSTextField: NSTextField {
override func becomeFirstResponder() -> Bool {
print("GSTextField Firstresponder")
////*** I need to set the button to be enabled here
return super.becomeFirstResponder()
}
}
Your NSTextField subclass needs to be able to communicate with the pushButton. The easiest way to do this is to pass a reference to the pushButton to your text field and then update the push button from there.
Update your ViewController like this:
override func viewDidLoad() {
super.viewDidLoad()
textField2.delegate = self
textField2.pushButton = pushButton
// Do any additional setup after loading the view.
}
And your GSTextField like this:
class GSTextField: NSTextField {
weak var pushButton: NSButton?
override func becomeFirstResponder() -> Bool {
print("GSTextField Firstresponder")
pushButton?.isEnabled = true
return super.becomeFirstResponder()
}
override func resignFirstResponder() -> Bool {
pushButton?.isEnabled = false
return super.resignFirstResponder()
}
}
It should be noted that while this works fine in this toy example, this is a sub-optimal solution to this problem because it tightly couples the pushButton and the GSTextField. A better solution would be to use delegation to communicate the focus changes to the ViewController, and let the ViewController handle the updates.
Your GSTextField would look like this:
protocol FocusObservable: class {
func didGainFocus(sender: Any)
func didLoseFocus(sender: Any)
}
class GSTextField: NSTextField {
weak var focusDelegate: FocusObservable?
override func becomeFirstResponder() -> Bool {
print("GSTextField Firstresponder")
focusDelegate?.didGainFocus(sender: self)
return super.becomeFirstResponder()
}
override func resignFirstResponder() -> Bool {
focusDelegate?.didLoseFocus(sender: self)
return super.resignFirstResponder()
}
}
And then you would add protocol conformance to the ViewController:
extension ViewController: FocusObservable {
func didGainFocus(sender: Any) {
pushButton.isEnabled = true
}
func didLoseFocus(sender: Any) {
pushButton.isEnabled = false
}
}
and set the focusDelegate of the text field:
override func viewDidLoad() {
super.viewDidLoad()
textField2.delegate = self
textField2.focusDelegate = self
// Do any additional setup after loading the view.
}
My save button is hidden with the function saveBtnHidden() in the code below. However, the save button won't reappear when text is typed into the text field. I have tried multiple solutions similar to this. Every time that I type into the text field, the save button just won't show up.
import UIKit
class TableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var saveBtn: UIButton!
#IBOutlet var nicknameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
saveBtnHidden()
}
func saveBtnHidden() {
if (nicknameField.text?.isEmpty ?? true) {
// is empty
saveBtn.isHidden = true
} else {
saveBtn.isHidden = false
}
}
#IBAction func saveBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "nextPage", sender: nil)
}
}
You are getting this error because your function saveBtnHidden() is only called once in viewDidLoad(). It does not get called again when the text in your text field changes. To detect when text changes, you will need to add a target to your text field that calls a function when it changes (.editingChanged) like this:
nicknameField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
Then in the textFieldDidChange call your saveBtnHidden() function:
func textFieldDidChange(_ textField: UITextField) {
saveBtnHidden()
}
Code adapted from: How do I check when a UITextField changes?
Use delegate to be notify of any change. Delegates is a key part of iOS development and Apple's framework.
class TableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var saveBtn: UIButton!
#IBOutlet var nicknameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
saveBtnHidden()
nicknameField.delegate = self
}
func textFieldDidChange(_ textField: UITextField) {
saveBtnHidden()
}
// More of your source code below...
I want to pass a Bool value from on view controller to another without the help of segues. So i referred & got Delegates.
I have applied delegates in my App. But the Delegate method is not being called. I don't know where i am making the mistake.
So Please help me.
MainViewController
class MainViewController: UIViewController, WriteValueBackDelegate {
#IBOutlet weak var LoginButton: UIButton!
var LoggedInL :Bool?
override func viewDidLoad() {
super.viewDidLoad()
}
func writeValueBack(value: Bool) {
println("Delegate Method")
if (value == true){
LoginButton.setTitle("My Profile", forState:UIControlState.Normal)
}
}
Second View Controller
class LoginController: UIViewController {
#IBOutlet weak var LoginLabel: UILabel!
#IBOutlet weak var email: UITextField!
#IBOutlet weak var pwd: UITextField!
var LoggedInL :Bool?
var mydelegate: WriteValueBackDelegate?
override func viewDidLoad() {
super.viewDidLoad() }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func onSubmit(sender: AnyObject) {
Alamofire.request(.GET, "http://www.jive.com/index.php/capp/user_verification/\(email.text)/\(pwd.text)")
.responseJSON { (_, _, data, _) in
println(data)
let json = JSON(data!)
let name = json["first_name"].stringValue
let status = json["valid_status"].intValue
println(status)
var e = self.email.text
println(e)
self.LoginLabel.text = "Hey \(name)!"
if status == 1{
println("Correect")
self.LoggedInL = true
self.mydelegate?.writeValueBack(true)
}else {
self.LoggedInL = false
println("Error")
}
}
navigationController!.popViewControllerAnimated(true)
}
}
protocol WriteValueBackDelegate {
func writeValueBack(value: Bool)
}
you didn't initialize the delegate, and no need to, delegates are usually for async callbacks. do that instead:
class MainViewController: UIViewController {
static var sharedInstace : MainViewController?;
#IBOutlet weak var LoginButton: UIButton!
var LoggedInL :Bool?
override func viewDidLoad() {
super.viewDidLoad()
MainViewController.sharedInstace = self; //this is better from init function
}
func writeValueBack(value: Bool) {
println("Delegate Method")
if (value == true){
LoginButton.setTitle("My Profile", forState:UIControlState.Normal)
}
}
}
in login view controller
MainViewController.sharedInstance?.writeValueBack(true)
In MainViewControlleryou need a reference of the LoginController instance maybe with an IBOutlet and then set the delegate in viewDidLoad
#IBOutlet weak var loginController : LoginController!
override func viewDidLoad() {
super.viewDidLoad()
loginController.mydelegate = self
}