How can I deal with @objc inference deprecation with #selector() in Swift 4?
The fix-it is correct – there's nothing about the selector you can change in order to make the method it refers to exposed to Objective-C.
The whole reason for this warning in the first place is the result of SE-0160. Prior to Swift 4, internal
or higher Objective-C compatible members of NSObject
inheriting classes were inferred to be @objc
and therefore exposed to Objective-C, therefore allowing them to be called using selectors (as the Obj-C runtime is required in order to lookup the method implementation for a given selector).
However in Swift 4, this is no longer the case. Only very specific declarations are now inferred to be @objc
, for example, overrides of @objc
methods, implementations of @objc
protocol requirements and declarations with attributes that imply @objc
, such as @IBOutlet
.
The motivation behind this, as detailed in the above linked proposal, is firstly to prevent method overloads in NSObject
inheriting classes from colliding with each other due to having identical selectors. Secondly, it helps reduce the binary size by not having to generate thunks for members that don't need to be exposed to Obj-C, and thirdly improves the speed of dynamic linking.
If you want to expose a member to Obj-C, you need to mark it as @objc
, for example:
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(foo), for: .touchUpInside)
}
@objc func foo() {
// ...
}
}
(the migrator should do this automatically for you with selectors when running with the "minimise inference" option selected)
To expose a group of members to Obj-C, you can use an @objc extension
:
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
This will expose all the members defined in it to Obj-C, and give an error on any members that cannot be exposed to Obj-C (unless explicitly marked as @nonobjc
).
If you have a class where you need all Obj-C compatible members to be exposed to Obj-C, you can mark the class as @objcMembers
:
@objcMembers
class ViewController: UIViewController {
// ...
}
Now, all members that can be inferred to be @objc
will be. However, I wouldn't advise doing this unless you really need all members exposed to Obj-C, given the above mentioned downsides of having members unnecessarily exposed.
Swift 3 @objc interference issue not being fixed :-(
- Click on the project (the first thing in the massive drop-down list)
- Click on the
Targets
section that appears - Search for the
Swift 3 @objc interference
section - Turn it
On
and fix any warnings/errors that pop up - Turn it to
Default
and your project should run without any issues
Why do I have to use public to expose func with Swift 4 @objc inference
I think these are two different things.
"Swift declarations marked with the private or fileprivate modifier do
not appear in the generated header.
is Followed by
Private declarations are not exposed to Objective-C unless they are explicitly marked with @IBAction, @IBOutlet, or @objc.
This can be read as saying a function must have the explicit marking to be exposed to Objective-C, and (separately) if marked private it will not be included in the header.
I'm not sure why something would need to be exposed without being visible, (I'm not familiar enough with the runtime to speak to that). However the closest Objective-C analogue to private
is to not be included in the header, so it makes sense to have that behavior match.
Argument of #selector does not refer to an '@objc' method, property or initializer
Selector() : It receives string/ string-literal as a parameter. It was used previously and #selector
is upgraded definition.
#selector : You are trying to pass a string in #selector
whereas it takes Objective-C type function reference. Correct example is:
NotificationCenter.default.addObserver(self, selector: #selector(peerChangedNotification(notification:)), name: NSNotification.Name("MPC_DidChangeStateNotification"), object: nil)
Related Topics
Is Swift Pass by Value or Pass by Reference
Instantiated Optional Variable Shows as Nil in Xcode Debugger
Input from the Keyboard in Command Line Application
Swift 2 - Pattern Matching in "If"
How to Do a Swift For-In Loop With a Step
Computed Read-Only Property VS Function in Swift
Selecting Global or Object Print Function
Why Create "Implicitly Unwrapped Optionals", Since That Implies You Know There's a Value
How to Print the Type or Class of a Variable in Swift
Swift Protocol Extension Method Is Called Instead of Method Implemented in Subclass
Non-'@Objc' Method Does Not Satisfy Optional Requirement of '@Objc' Protocol
Why Are Emoji Characters Like 👩👩👧👦 Treated So Strangely in Swift Strings
Get Terminal Output After a Command Swift
What Sorting Algorithm Does Swift Implement For Its Standard Library