I’ve ended up editing SDK header files to silence some deprecation warnings.
Now there’s one less distracting warning you can do nothing about.
I know, it’s dirty. But if there’s no replacement API available in the current SDK, it should be safe. Once a new version of Xcode comes out, the change will get overwritten and you will see the warning again. Then you can test the new SDK and OS to make sure the deprecated API is still available and did not get a proper replacement.
In cases like yours (it took a lot of scrolling to work out that you're talking about SMJobSubmit :-) I generally resolve this conundrum by writing a small Objective-C wrapper around the function and then suppressing the warning on the Objective-C side. This also gives you the opportunity to expose a nicer API. For example, with this code:
To add to this discussion: sometimes a warning is not actually valid and just confuses matters. An example case could be because you implemented something for performance reasons in a non-standard way and it would be very nice to be able to suppress such a warning.
Example:
When implementing a LinkedList in a performant manner it is beneficial to avoid letting ARC do its magic and manually retain/release the nodes instead. I have this in my implementation:
private class Node<Element> {
var value: Element
// Usage of unowned is required to avoid running into troubles when deallocating a big list: will recursively call dealloc otherwise leading to a BAD_ACCESS
unowned var next: Node<Element>?
unowned var previous: Node<Element>?
init(_ value: Element) {
self.value = value
// Perform a manual retain call on init
self.retain()
}
func retain() {
_ = Unmanaged.passUnretained(self).retain()
}
func release() {
_ = Unmanaged.passUnretained(self).release()
}
func autorelease() {
_ = Unmanaged.passUnretained(self).autorelease()
}
}
Now I defined a function insert as follows. The warning which is displayed is not actually valid. I'm doing this on purpose to avoid unneeded retain/release calls by ARC, and the Node is retained in the initializer.
private final class LinkedListStorage<Element> {
unowned var head: Node<Element>?
unowned var tail: Node<Element>?
var count = 0
....
func insert(_ element: Element, relativeTo: Node<Element>?, before: Bool) {
//WARNING: Instance will be immediately deallocated because variable 'node' is 'unowned'
unowned let node = Node(element)
if let anchor = relativeTo {
if before {
node.next = anchor
node.previous = anchor.previous
anchor.previous?.next = node
anchor.previous = node
} else {
node.previous = anchor
node.next = anchor.next
anchor.next?.previous = node
anchor.next = node
}
}
if node.next == nil {
tail = node
}
if node.previous == nil {
head = node
}
count += 1
}
}
This is the kind of code that voids Swift’s warranty. If you want to manage memory manually, just make Node a struct and have next and previous be UnsafeMutablePointer<Node>. It’s more honest with the optimizer and, really, it’s more honest with yourself.
I’m also a fan of some annotation in my source code that can hide individual warnings. Deprecation warnings seem to be the only ones I’ve had issue with, but I’m split on if this annotation should be deprecation specific or cover all types of warnings. I’ve been turning off warnings as errors with each SDK bump to see what new deprecation warnings arrive and bumping my deployment target. But after fixing the warnings that I can, I lower the deployment target back down (on frameworks) to silence the warnings. This is so hackey, but the only way to hide these. I’d love to fix my code but have no way to. Need to use MD5 in a non-cripto context for legacy reasons? Or how about use OpenGL on iOS 12+ (can’t switch to metal because not all iOS 12 devices have full metal support dispute OpenGL being deprecated on 12)? Allowing warnings to persist in a project is really just a recipe to not notice new warnings when you do accidentally do something wrong.
I don't know, but I shouldn't have to import a 3rd party library to work around a deprecation warning, when the SDK has a working function to do the same thing.
Didn't know that CryptoKit existed, seems kinda crazy to mark MD5 as deprecated in one framework and not in another. If you intend to move it, then the deprecation warning's message should say so.
I still feel the point stands, that we need some way to hide individual warnings. I liked the idea of the annotation hiding the warning for a single Swift version. This way you will see the warning on a regular basis, and will need to rehide it to confirm you are ok with it.
// Silences a warning, but only in Swift 5.1
@silenceWarning(Swift5_1)
I'd also be good if we tie it to SDK version instead, but can see how that wouldn't work well for Linux use.
I guess the thinking is that the Insecure namespace is enough in CryptoKit land.
I do agree with the wider point. CC_MD5 should probably not have been annotated as deprecated; it's not really the right tool for the job. Swift's principled stance is theoretically ideal, but frameworks — including Apple's — often use warnings when they probably shouldn't and having no way to override that is annoying.
I don't want to globally disable warnings. I want to see all deprecations. But I want to silence specific ones.
You can argue all you want that the root cause should be fixed, even if it means editing dependencies and updating your whole codebase. But how am I supposed to change UIKit?
Here's the relevant bit of code:
private func prepareForPresenting(_ viewController: UIViewController) {
guard #available(iOS 13, *),
viewController is UIDocumentMenuViewController,
DisplayUtils.phone else { return }
guard let webViewController = viewControllers.last as? WebViewModuleViewController,
let popoverPresentationController = viewController.popoverPresentationController else { return
}
// Set sourceView and sourceRect for UIDocumentMenuViewController presenter from a WebView
// Based on: https://stackoverflow.com/questions/58164583
popoverPresentationController.sourceView = webViewController.webView
popoverPresentationController.sourceRect = CGRect(origin: webViewController.lastWebViewTapPosition, size: .zero)
}
Yes, UIDocumentMenuViewController got deprecated in iOS 11. Yet WKWebView still uses it under the hood, even as of iOS 14, and is causing a crash that is 100% reproducible with the new iOS 13 style modal sheet presentation.
So what are my options?
Globally disable all deprecations. Amazing, now I don't see any deprecation warnings.
Get used to always seeing 1 warning in the Xcode build output. Amazing. Broken window effect anyone?
Remove it from my code at let my users enjoy the crashes?
This is of course an important part of any response, but it’s also extremely unhelpful in addressing the concerns raised.
Even if this does get fixed, this is out in the world within existing iOS versions, and needs to be handled by anyone presenting web views on these iOS versions which happens to invoke this screen, even if it does get fixed in later releases.
I believe this points out a flaw in the current deprecation warning system, that you still may require to use and work with deprecated types, because any framework or library, including other system libraries, may still be using them and you need to work with them regardless of the “best practice”.
It would be nice to have this addressed rather than avoiding and ignoring the real-world issue.