I have a Swift library which is heavily reliant on obj.valueForKey() from NSObject.
After migrating to Swift 4 I've found that these calls always crash with the error "this class is not key value coding-compliant for the key..." unless the property I'm looking for is declared with #objc.
Is it now mandatory to declare properties with #objc for them to be found with this method? Is there an alternative?
When you performed the migration Xcode asked about #objc inference and you probably selected the new type instead of Swift3.
Possible solutions:
Use #objc
Use #objc on each method, as needed instead of the whole class.
Use #objcMembers
You could just use #objcMembers on the class.
Applying #objcMembers attribute to a class implicitly adds the #objc attribute to all of its Objective-C compatible members.
Writing Swift Classes and Protocols with Objective-C Behavior
Keep in mind: because applying the #objc attribute can increase the compiled size of an app and adversely affect performance, only apply the #objcMembers attribute on declarations when each member needs to have the #objc attribute applied.
Switch inference to the old behavior
You can also change the project's behavior under:
Build Settings > Swift 3 #objc Inference > On/Off
Related questions:
The use of Swift 3 #objc inference in Swift 4 mode is deprecated?
How can I deal with #objc inference deprecation with #selector() in Swift 4?
Briefly, while using Xcode 9 Beta, I have run into the following warning:
The use of Swift 3 #objc inference in Swift 4 mode is deprecated. Please address deprecated #objc inference warnings, test your code with “Use of deprecated Swift 3 #objc inference” logging enabled, and disable Swift 3 #objc inference.**
After some research, I still have no idea how to fix the issue.
I would greatly appreciate any tips on how to fix this issue as well as an explanation of what is going on.
My goal is to grasp a better understanding of what is happening with my code.
I got rid of this warning by changing the "Swift 3 #objc Inference" build setting of my targets to "Default".
From this article:
Before Swift 4, the compiler made some Swift declarations automatically available to Objective-C. For example, if one subclassed from NSObject, the compiler created Objective-C entry points for all methods in such classes. The mechanism is called #objc inference.
In Swift 4, such automatic #objc inference is deprecated because it is costly to generate all those Objective-C entry points. When "Swift 3 #objc Inference" setting is set to "On", it allows the old code to work. However, it will show deprecation warnings that need to be addressed. It is recommended to "fix" these warnings and switch the setting to "Default", which is the default for new Swift projects.
Please also refer to this Swift proposal for more information.
- What is #objc inference? What is going on?
In Swift 3, the compiler infers #objc in a number of places so you wouldn't have to. In other words, it makes sure to add #objc for you!
In Swift 4, the compiler no longer does this (as much). You now must add #objc explicitly.
By default, if you have a pre-Swift 4 project, you will get warnings about this. In a Swift 4 project, you will get build errors. This is controlled via the SWIFT_SWIFT3_OBJC_INFERENCE build setting. In a pre-Swift 4 project this is set to On. I would recommend to set this to Default (or Off), which is now the default option on a new project.
It will take some time to convert everything, but since it's the default for Swift 4, it's worth doing it.
- How do I stop the compiler warnings/errors?
There are two ways to go about converting your code so the compiler doesn't complain.
One is to use #objc on each function or variable that needs to be exposed to the Objective-C runtime:
#objc func foo() {
}
The other is to use #objcMembers by a Class declaration. This makes sure to automatically add #objc to ALL the functions and variables in the class. This is the easy way, but it has a cost, for example, it can increase the size of your application by exposing functions that did not need to be exposed.
#objcMembers class Test {
}
- What is #objc and why is it necessary?
If you introduce new methods or variables to a Swift class, marking them as #objc exposes them to the Objective-C runtime. This is necessary when you have Objective-C code that uses your Swift class, or, if you are using Objective-C-type features like Selectors. For example, the target-action pattern:
button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)
- Why would I not mark everything #objc?
There are negatives that come with marking something as #objc:
Increased application binary size
No function overloading
Please keep in mind that this is a very high-level summary and that it is more complicated than I wrote. I would recommend reading the actual proposal for more information.
Sources:
https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html#//apple_ref/doc/uid/TP40014216-CH5-ID86
Migrator cannot identify all the functions that need #objc
Inferred Objective-C thunks marked as deprecated to help you find them
• Build warnings about deprecated methods
• Console messages when running deprecated thunks
I had this warning with "Swift 3 #objc Inference" = "Default" setting. Then I realized that is was set for the Project - not for the target. So, make sure that you have "Default" setting in your target to get rid of the warning.
You can simply pass to "default" instead of "ON". Seems more adherent to Apple logic.
(but all the other comments about the use of #obj remains valid.)
Indeed, you'll get rid of those warnings by disabling Swift 3 #objc Inference.
However, subtle issues may pop up. For example, KVO will stop working.
This code worked perfectly under Swift 3:
for (key, value) in jsonDict {
if self.value(forKey: key) != nil {
self.setValue(value, forKey: key)
}
}
After migrating to Swift 4, and setting "Swift 3 #objc Inference" to default, certain features of my project stopped working.
It took me some debugging and research to find a solution for this.
According to my best knowledge, here are the options:
Enable "Swift 3 #objc Inference" (only works if you migrated an existing project from Swift 3)
Mark the affected methods and properties as #objc
Re-enable ObjC inference for the entire class using #objcMembers
Re-enabling #objc inference leaves you with the warnings, but it's the quickest solution. Note that it's only available for projects migrated from an earlier Swift version.
The other two options are more tedious and require some code-digging and extensive testing.
See also https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md
I'm an occasional iOS dev (soon to be more) but I still couldn't find the setting as guided by the other answer (since I did not have that Keychain item the answer shows), so now that I found it I thought I might just add this snapshot with the highlighted locations that you will need to click and find.
Start in the upper left
Choose the project folder icon
Choose your main project name below the project folder icon.
Choose Build Settings on the right side.
Choose your project under TARGETS.
Scroll very far down (or search for the word inference in search
text box)
You can try to "Pod update" and/or "flutter clean"
I also set this setting in xcode.
The Objective-C interface setting is as follows:
Swift 3 #objc Inference
The use of Swift 3 #objc inference in Swift 4 mode is deprecated. Please address deprecated #objc inference warnings, test your code with “Use of deprecated Swift 3 #objc inference” logging enabled, and then disable inference by changing the "Swift 3 #objc Inference" build setting to "Default" for the "XMLParsingURL" target.
got to the
First step got Build Setting
Search in to Build Setting Inference
change swift 3 #objc Inference Default
enter image description here
The use of Swift 3 #objc inference in Swift 4 mode is deprecated?
use func call #objc
func call(){
foo()
}
#objc func foo() {
}
All you need just run a test wait till finish, after that go to Build Setting, Search in to Build Setting Inference,
change swift 3 #objc Inference to (Default). that's all what i did and worked perfect.
On top of what #wisekiddo said, you can also modify your build settings in the project.pbxproj file by setting the Swift 3 #obj Inference to default like SWIFT_SWIFT3_OBJC_INFERENCE = Default; for your build flavors (i.e. debug and release), especially if you're coming from some other environment besides Xcode
Xcode 8 beta 4 no longer recognizes Foundation class AttributedString.
I've reproduced it in this simple playground example:
//: Playground - noun: a place where people can play
import Foundation
let attrStr1 = NSAttributedString()
let attrStr2 = AttributedString() // Use of undeclared type 'AttributedString'
Since AttributedString was available in older Xcode 8 Swift 3 betas, I imagine this is a Foundation bug that needs to be fixed, rather than some source code error in Playground?
Although undocumented in the Xcode release notes, a version 2 update to Swift evolution proposal SE-0086 Drop NS Prefix in Swift Foundation has added the "NS" prefix back to several Foundation classes which previously dropped the prefix.
The reason is as follows:
If the class is planned to have a value-type equivalent in the near future, then keep the NS prefix. Examples: NSAttributedString, NSRegularExpression, NSPredicate.
So, the Swift AttributedString type will return at some point, as a struct next time, instead of being a class.
It sounds like some of these improvements will be "a focus area for Swift 4." For now, it's necessary to revert back to using the NSAttributedString class.
If you're curious to know how many types were affected by the SE-0086 v2 update, it looks like the revision affects ~32 types which had previously dropped the NS prefix for Swift 3.
I am creating a class that implements both the AVCaptureFileOutputDelegate and the AVCaptureVideoDataOutputSampleBufferDelegate protocols in Swift 2 (beta 3), but I am getting a compiler error due to the fact that both protocols define very similar functions (intentionally so; there are example Objective-C classes that implement both protocols).
The conflicting protocol extensions are AVCaptureFileOutputDelegate's captureOutput(_:didOutputSampleBuffer:fromConnection:) and AVCaptureVideoDataOutputSampleBufferDelegate's captureOutput(_:didOutputSampleBuffer:fromConnection:). The only difference in the function signatures is the type of the captureOutput argument (AVCaptureFileOutput and AVCaptureOutput respectively).
I thought that using AVCaptureFileOutput in my function definition might work, since it is a subclass of AVCaptureOutput, but the compiler still reports the error:
Objective-C method 'captureOutput:didOutputSampleBuffer:fromConnection:' provided by method 'captureOutput(_:didOutputSampleBuffer:fromConnection:)' conflicts with optional requirement method 'captureOutput(_:didOutputSampleBuffer:fromConnection:)' in protocol 'AVCaptureVideoDataOutputSampleBufferDelegate'
Is there a way to work around this, or to force the compiler to use the function for both protocols? Any idea if this is just a Swift 2.0 issue that should be reported, or an area where Swift has a different approach than what is normally used in Objective-C?
Thanks.
I was not able to find a workaround, at least given the current Swift beta. I instead used a separate class as the AVCaptureFileOutputDelegate delegate. Not elegant, but functional.
Just started to use Xcode6 beta 4 and have come up against an issue that was not there before. I define my NS_ENUM in my objective-c as follows:
typedef NS_ENUM( NSInteger, ToolbarType ) {
tb_closed_k = 0,
tb_text_k = 10,
tb_shape_k,
tb_undefined_k
};
Then in my swift code i want to set a variable to one of these values:
var test = ToolbarType. tb_undefined_k
This was working without issues in beta 3 but now I get an error that :
'ToolbarType' does not have a member named 'var test = ToolbarType. tb_undefined_k'
After investigating further, if I type the enum type followed by a ., auto completion shows me the options and it suggests the value to be:
ToolbarType.b_undefined_k
is seems very odd. Is this a bug or some kind of naming convention? I am afraid if I use these suggested values, in the next release they all become broken.
Any suggestions. Thanks.
Reza
After playing around I found that if I added a value to the end of the enum that did not in anyway conform to the naming convention of the values that proceeded it then the error would go away. In fact I just added "dummy" to the end my list of enums and it all started to work