5

Following code works perfectly in swift 3.x but not in swift 4.

let selector = "managerDidDetectedStation:"
let observer = <UIViewController subclass object>
let station = <Station Object>

if observer.responds(to: Selector(selector) {         
    observer.perform(Selector(selector), with: station)
}

observer.responds(to: Selector(selector) always returns false. Does anybody aware of any change in this api in swift4?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Abid Hussain
  • 1,529
  • 1
  • 15
  • 33
  • 1
    UIViewController does not have managerDidDetectedStation method, does it? – Andrey Chernukha Oct 03 '17 at 13:17
  • It does. func managerDidDetectedStation(_ station : Station) { } – Abid Hussain Oct 03 '17 at 13:19
  • 2
    Is this a method you've added in Swift but haven't annotated as `@objc`? See this Q&A: https://stackoverflow.com/q/44390378/2976878. But you should really use `#selector` here; the compiler can catch these mistakes for you. – Hamish Oct 03 '17 at 13:19
  • @AbidHussain hmm. Can you provide a reference for this method? I'm curious to see the docs. UIViewController class reference does not mention this method – Andrey Chernukha Oct 03 '17 at 13:22
  • Also why are you using `responds(to:)` + `perform(_:with:)`? Is this genuinely a method that you're dynamically adding at runtime, or is this just an optional protocol requirement? If it's the latter, Swift makes the method (on the protocol type) an optional, you can just use optional chaining with it. – Hamish Oct 03 '17 at 13:29
  • Hamish it's the baggage I got from another developer. I'm converting his project to Swift4. The requirement was to have 1-N communication and that's why MonitoringManger singleton has an array of observers which all get notified through this method. – Abid Hussain Oct 03 '17 at 13:33
  • @AbidHussain Ah okay; you're quite correct that it needs a redesign :) For simple cases, you may want to consider just storing an array of closures. – Hamish Oct 03 '17 at 13:37

1 Answers1

12

You need to add @objcMembers at top of observer class

For Ex. if observer is a object of XYZClass class then write

@objcMembers
class XYZClass : NSObject
{
  // Your Stuff
}

OR

Another way is to put @objc to start of your method like below.

 @objc func managerDidDetectedStation...
foundry
  • 31,615
  • 9
  • 90
  • 125
iPatel
  • 46,010
  • 16
  • 115
  • 137
  • Unless you really need *all* Obj-C compatible members exposed, I wouldn't advise `@objcMembers`. – Hamish Oct 03 '17 at 13:21
  • 1
    thanks iPatel. I guess I need to implement proper delegation instead of this dumbass solution. – Abid Hussain Oct 03 '17 at 13:29
  • Quick note with Xcode 10: I had to use `@objcMembers`, not `@objMembers`. I'm new to Swift, so I'm not sure if that's a typo in the answer or a recent adjustment to the language (which seems to change faster than a teenager's fashion taste). – sherb Mar 29 '19 at 21:26