Editor Placeholder Error - swift

I am trying to add search capability to a table view controller.
I am getting an error saying I have an editor placeholder in my source code. It is in the updateSearchResults method where I am implementing the UISearchResultsUpdating protocol.
Here is the code generating this error:
import UIKit
class SearchTable : UITableViewController {
}
extension SearchTable : UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
}
}
I have not implemented this method just yet but will later - I am just wondering why this error is surfacing as I have provided the stub for the method and will return to it later?

Related

How to create separate data mapping file with function names in Swift

I have a macOS app that I'm creating in Swift and I have integrated an external HID device that has a number of controls on it.
The HID part is done where I am receiving all of the hid commands from the device and I am trying to create a mapping file where I can maintain the HID key mappings in a separate swift file.
All I want in that file is the data and what I want to do is this;
raw hid data is received from HID device (In ViewController)
Lookup the function name assigned to this hid data (In separate file)
Run the function that is mapped to that key. (Function located in the main ViewController)
So far I have the external swift file setup with all of the mapping and that all works fine but my issue is when I try to call the looked up function in the ViewController, it says the function can't be found in the scope.
Initially I thought I would use a delegate but the external file isn't a viewcontroller, just a separate swift file so I don't know if I can do that?.
I've tried searching but everything I've found is calling a function from another ViewController which I'm not. It's very possible I'm not using the best approach and my goal is to just keep all of the mapping in a separate file as there is a lot and it woudl be easier to maintain.
Any suggestions are appreciated.
This is one way to achieve this. It can get tedious. You can totally skip writing out a separate protocol for the delegate, but this is cleaner design.
protocol HIDMessageDelegate: AnyObject {
// example messages
func message1()
func message2()
func message3()
}
class HIDMessageParser {
static weak var delegate: HIDMessageDelegate?
static func parseHIDMessage() {
var condition = 0
// this is where your switch statement will go and you'll parse things and call the relevant delegate method
switch (condition) {
default:
delegate?.message1()
}
}
}
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
HIDMessageParser.delegate = self
}
}
extension MyViewController: HIDMessageDelegate {
func message1() {
}
func message2() {
}
func message3() {
}
}
You can simply create a UIViewController as the external file and add it as a property to the main ViewController.
In the external file add this.
#IBOutlet var uiViewController: UIViewController!
In the ViewController add this.
var externalFileViewController: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
externalFileViewController = externalFileViewController?.loadView()
// If we have an object then load it
if let viewController = externalFileViewController {
viewController.view.frame = view.frame
viewController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
view.addSubview(viewController.view)
uiViewController = viewController
}
}
Now in the viewController look up the functions to be called from the external file and call them using the function name.
The functions are defined in the external file using #IBAction.
Let me know if you have any questions.

Non-'#objc' method 'didFinish' does not satisfy requirement of '#objc' protocol 'YPSignatureDelegate'

We are using YPDrawSignature from here to draw a signature on the IOS App.
We are getting the following error on the UIViewController.
Non-'#objc' method 'didFinish' does not satisfy requirement of '#objc' protocol 'YPSignatureDelegate'
The UIViewController is this.
class SignatureViewController: UIViewController , UICollectionViewDelegate, UICollectionViewDataSource, YPSignatureDelegate {
func didStart(_ view : YPDrawSignatureView) {
// print("Started Drawing")
}
func didFinish(_ view : YPDrawSignatureView){
// func didFinish (){
}
}
UPDATE.
We tried the following.
#objc func didStart(_view : YPDrawSignatureView) {
// print("Started Drawing")
}
But still get the same error.
The YPDrawSignatureView has the following Delegate
#objc
public protocol YPSignatureDelegate: class {
func didStart(_ view : YPDrawSignatureView)
func didFinish(_ view : YPDrawSignatureView)
}
extension YPSignatureDelegate {
func didStart(_ view : YPDrawSignatureView) {}
func didFinish(_ view : YPDrawSignatureView) {}
}
I've downloaded YPSignatureView, and did similar to what you have. All I implemented was:
func didStart(_ view : YPDrawSignatureView) {}
func didFinish(_ view : YPDrawSignatureView) {}
and of-coarse assigning a delegate to the view, with those methods implemented by the delegate. And I don't get any errors. Make sure you haven't accidentally changed the YPSignatureView.swift file by clicking on the red button that says Fix as a suggestion. Before I implemented didStart and didFinish, I did get the same error as you have, with a button that says Fix in YPSignatureView. Clicking on that silently changes code within YPSignatureView.swift. Make sure YPSignatureView.swift is pristine and implement the above two functions and you should be fine. Re-download the file to be safe, implement those two methods as above, and thats it.
My didStart() and didFinish() functions are called when touches begins and finishes respectively. Let me know how you go.
Update: as mentioned above, you probably clicked on these two error messages here:
Do not do that. If you did then get a fresh copy of that file then just implement the protocol methods without any #objc. Hit Command + Shift + k to clean build folder and then build again. I did not get any errors after that, runs fine, and yours should too.
In your implementation, you forgot to put the space between _ and view;
Change
func didFinish(_view : YPDrawSignatureView) to
func didFinish(_ view : YPDrawSignatureView)

Weak and delegate fail-warnings when trying to update tableview through delegate method

I been struggling to update my tableview through another class I made.
I then found this stackoverflow solution:
How to access and refresh a UITableView from another class in Swift
But when I follow it step by step and implement all the codes, I get the following errors:
My line:
weak var delegate: UpdateDelegate?
Gets the warning
'weak' may only be applied to class and class-bound protocol types, not 'UpdateDelegate'
And my line:
self.delegate.didUpdate(self)
Gets warning:
Instance member 'delegate' cannot be used on type 'APIgetter'
Could this be because the code is old and I'm using swift 4? else I cannot see why this should be failing. I hope you can help me :)
Update:
My Protocol:
protocol UpdateDelegate: AnyObject {
func didUpdate(sender: APIgetter)
}
Snippet from my ViewController containing the tableview:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UpdateDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
APIgetter.addDataFromSQL()
let updates = APIgetter()
updates.delegate = self
}
//update func
func didUpdate(sender: APIgetter) {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
My APIgetter class in APIgetter.swift:
class APIgetter {
weak var delegate: UpdateDelegate?
class func addDataFromSQL (){
//Code to fetch data from API
//Code that comes after DispatchQueue.global & DispatchQueue.main and my result being executed
//result
self.delegate.didUpdate(self)
just update your protocol definition.
protocol UpdateDelegate: class {
// protocol body
}
or
protocol UpdateDelegate: AnyObject {
// protocol body
}
This is needed (as of Swift 4 I think) because classes are reference types and you can only use a weak reference on reference types. Not value types like structs.
UPDATE: You cannot access a property/instance member from a static function the way that you currently are. Remove the class keyword from the function and it should work.
If you want/need to use a single instance of this class throughout your application you can use a static property to make it a Singleton
class APIgetter {
static let shared: APIgetter = APIgetter()
}
Then you would be able to access it like this:
APIgetter.shared.addDataFromSQL()
You could also update the delegate in the same way before calling your function.
APIgetter.shared.delegate = self
I think in this case though I would use a Singleton without the delegate. Just use a completion handler in your function. Setting and changing the delegate on a shared instance could have some side effects if not managed carefully.

ViewController + Storyboard setting up validation with controlTextDidChange

Trying to setup validation for a few text fields in a new (and very small) Swift Mac app. Following various other topics here on SO and a few other examples, I can still not get controlTextDidChange to propagate (to my ViewController).
E.g: How to live check a NSTextField - Swift OS X
I have read at least a dozen variations of basically that same concept. Since none of the accepted answers seem to work I am just getting more and more confused by something which is generally a fairly simple task on most platforms.
I have controlTextDidChange implemented to just call NSLog to let me know if I get anything.
AppDelegate should be part of the responder chain and should eventually handle controlTextDidChange but I see nothing there either.
Using the current Xcode I start a new project. Cocoa app, Swift, Storyboard and nothing else.
From what I can gather the below isolated example should work. In my actual app I have tried some ways of inserting the ViewController into the responder chain. Some answers I found suggested it was not always there. I also tried manually adding the ViewController as the delegate in code theTextField.delegate = self
Nothing I have done seems to get text changed to trigger any events.
Any ideas why I have so much trouble setting up this delegation?
My single textfield example app
Storyboard is about as simple as it gets:
AppDelegate
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSTextFieldDelegate, NSTextDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("AppDelegate::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
ViewController
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate, NSTextDelegate {
#IBOutlet var theTextField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("ViewController::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
I think the samples you're following are a bit out-of-date.
Try...
override func controlTextDidChange(_ notification: Notification) {
...as the function definition for your method in your NSTextFieldDelegate.

How do I make a UITableViewController conform to protocol UISearchResultsUpdating?

I have a UITableViewController class in which I am implementing a UISearchController. I've added the following delegates:
class EmployeesTableView: UITableViewController, NSFetchedResultsControllerDelegate,UISearchResultsUpdating{
I'm importing both UIKit and CoreData. I'm getting the following error:
"Type 'CustomTableViewController' does not conform to protocol UISearchResultsUpdating"
What do I need to do to make the controller conform to the protocol?
Swift 3:
func updateSearchResults(for searchController: UISearchController) {
// code here
}
When you add protocols to your class definition, the easiest way is to mouse over the protocol name and command click its name. This will pull up its definition. With protocol definitions, they usually have methods immediately following them. If a method is required it will be at the top, if it has optional in front, then it isn't required in order to conform.
In the case of `UISearchResultsUpdating, it only has one method and it is required. Just copy the method, or multiple methods and click the back arrow to get back to your class. Paste the methods into your class, and implement them. If they were optional methods (in this case there are no optional methods), remove optional from the front. This is what I copied from the definition.
func updateSearchResultsForSearchController(searchController: UISearchController)
Then you update it to do what you want to do.
func updateSearchResultsForSearchController(searchController: UISearchController) {
//do whatever with searchController here.
}
As an additional example, command click on NSFechedResultsControllerDelegate. You will see that it has no required methods, but lots of optional ones. This information is usually found in the documentation as well, but I've found command + click to be the fastest way to find what I'm looking for.
Swift 3.0
//Make sure to import UIKit
import Foundation
import UIKit
class ViewController: UIViewController, UISearchBarDelegate {
var searchController = UISearchController()
override func viewDidLoad() {
//Setup search bar
searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
//Set delegate
searchController.searchResultsUpdater = self
//Add to top of table view
tableView.tableHeaderView = searchController.searchBar
}
}
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
print(searchController.searchBar.text!)
}
}