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

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)

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.

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.

Editor Placeholder Error

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?

Swift compiler segfaults with CGRects and #objc protocols

While writing an iOS app I noticed a weird error with CGRects and #objc protocols.
I managed to strip my code down to this, which produces the exact same stack trace :
import Foundation
#objc protocol TestClassDelegate {
optional func doSomethingWith(rect: CGRect)
}
class TestClass: NSObject {
var delegate: TestClassDelegate?
func callMyDelegate(myRectangle: CGRect) {
if let delegate = delegate {
delegate.doSomethingWith?(myRectangle)
}
}
}
print("I'LL NEVER COMPILE, SO YOU'LL NEVER SEE ME")
Just put this code in a main.swift file and try to compile. I intended to raise the issue on bugs.swift.org, but perhaps there's something I don't understand going on... Any idea ?
EDIT : Here's the issue on Swift's bug tracker (you'll find a stack trace there) : https://bugs.swift.org/browse/SR-2268
FOLLOWUP : Seems to be still broken in Swift 3 (see the issue on Swift's JIRA)

Implement protocol through extension [duplicate]

This question already has answers here:
Swift: Using protocol extension results in "unrecognized selector sent to instance"
(2 answers)
Closed 6 years ago.
I'm trying to create a protocol that wraps the process of using the UIImagePickerController to make it more stream-lined in my apps. I essentially have something like this:
public protocol MediaAccessor : UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func mediaCaptured(title: String, fileData: NSData, fileType: String)
}
and an extension that does all the heavy lifting of requesting the permission and handling the delegate methods:
public extension MediaAccessor where Self : UIViewController {
public func captureMedia() {
//All sorts of checks for picker authorization
let picker = UIImagePickerController()
picker.delegate = self
self.presentViewController(picker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
//implementation of the delegate in extension
//even though everything compiles, this method is not called on picker completion
}
}
So everything compiles, but implementing the UIImagePickerControllerDelegate through the extension doesn't seem to register. When I show the picker, it allows me to take a picture, but the didFinishPickingImage call never happens. If I move that call directly into the controller everything works fine, but the idea of this was to hide this stuff from the view controller for a very clean interface into allowing a controller to access media from the device. Is implementing protocol methods through an extension like this something that can't work? Is there something I can change to allow this to work, without having to implement the protocol directly in my view controller?
Cocoa is written in Objective-C. Objective-C can't see Swift protocol extension code. So it's unaware of that implementation of imagePickerController:didFinishPickingImage:. If you want a delegate method to be called by Cocoa, you need to put it where Cocoa can see it.