I'm dealing with an issue where Obj-C code can pass nil
to Swift methods that do not take Optional parameters.
I'm looking for a way for Xcode compiler to prevent this. It seems that all nullability annotations are for Swift to call Objc, not vice-versa.
Some example code:
// file1.swift
@objc
class Foo: NSObject {
@objc let date: Date? // default to nil
...
}
// file2.swift
extension Date {
@objc(doSomethingWithOtherDate:)
func doSomething(with otherDate: Date) {
print(date)
}
}
Then in Obj-c, we call the Swift method passing in an optional value, with nil
:
// file3.m
[Date.new doSomethingWithOtherDate:[Foo.new date]];
Is there a way to prevent this? How can we tell the compiler doSomethingWithOtherDate
does not take nil
.
Following up on this issue, passing a literal nil
on the call triggers a warning, which is very helpful. However, passing a nil
value does not trigger anything. The static analyzer does however find the issue if the nil reference is local.
However, if a nil
reference is passed via another object, the static analyzer fails to identify this issue.
I've made this repo to showcase this issue: https://github.com/eneko/ObjcCrashDemo
In general, no. Objective-C does not have enough understanding of nullability to detect every case.
If you explicitly pass nil you should get a warning "Null passed to a callee that requires a non-null argument". You can turn this into an error by adding -Werror=nonnull
to "Other Warning Flags" in your build settings.
However this is extremely limited. Even something as simple as NSDate* date = nil;
and passing that will produce no warning/error. Even adding a nonnull
property in Objective-C and passing that will not produce a warning/error.
I was able to find this article: https://fabiancanas.com/blog/2020/1/9/swift-undefined-behavior.html (search for the "Detecting nil when nil isn't possible" section). This article discusses a rather complex solution to the problem, but I would suggest the easier solution would be to declare your function argument type as Date!
(either a value or nil) and then perform a guard let
on the passed value before proceeding in the function body:
// file2.swift
extension Date {
@objc(doSomethingWithOtherDate:)
func doSomething(with otherDate: Date!) {
guard let od = otherDate else {
// do something else
return
}
print(date)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.