AnyObject, Any, and any: When to use which? By adminin Tutorials - March 24, 2022 Comments: 0 Views: 709 nyObject and Any got a new option any as introduced in SE-355, making it harder for us developers to know the differences. Each option has its use cases and pitfalls regarding when not to use them. Any and AnyObject are special types in Swift, used for type erasure, and don’t have a direct relationship with any. Be aware of the uppercase A in this article since I’ll cover both Any and any which have different explanations. Let’s dive into the details! When to use AnyObject? AnyObject is a protocol to which all classes implicitly conform. In fact, the standard library contains a type alias AnyClass representing AnyObject.Type. print(AnyObject.self) // Prints: AnyObject print(AnyClass.self) // Prints: AnyObject.Type All classes, class types, or class-only protocols can use AnyObject as their concrete type. To demonstrate, you could create an array of different types: let imageView = UIImageView(image: nil) let viewController = UIViewController(nibName: nil, bundle: nil) let mixedArray: [AnyObject] = [ // We can add both `UIImageView` and `UIViewController` to the same array // since they both cast to `AnyObject`. imageView, viewController, // The `UIViewController` type conforms implicitly to `AnyObject` and can be added as well. UIViewController.self ] Only classes conform to AnyObject, meaning that you can use it to restrict protocols to be implemented by reference types only: protocol MyProtocol: AnyObject { } You can use AnyObject if you need the flexibility of an untyped object. I could give examples of using a collection of any objects that you can cast back to a concrete type when used, but I would like to suggest something different instead. I can’t remember using AnyObject in any of my projects, since I was always able to use concrete types instead. Doing so also leads to more readable code that is easier to understand by fellow developers. To demonstrate this to you, I’ve created this example method which configures an image into a destination container: func configureImage(_ image: UIImage, in imageDestinations: [AnyObject]) { for imageDestination in imageDestinations { switch imageDestination { case let button as UIButton: button.setImage(image, for: .normal) case let imageView as UIImageView: imageView.image = image default: print("Unsupported image destination") break } } } By using AnyObject as our destination, we always need to cast and consider casting failures using the default implementation. My preference would always be to rewrite this using concrete protocols instead: // Create a protocol to act as an image destination. protocol ImageContainer { func configureImage(_ image: UIImage) } // Make both `UIButton` and `UIImageView` conform to the protocol. extension UIButton: ImageContainer { func configureImage(_ image: UIImage) { setImage(image, for: .normal) } } extension UIImageView: ImageContainer { func configureImage(_ image: UIImage) { self.image = image } } // Create a new method using the protocol as a destination. func configureImage(_ image: UIImage, into destinations: [ImageContainer]) { for destination in destinations { destination.configureImage(image) } } The resulting code is cleaner, readable, and no longer requires handling unsupported containers. Instances are required to conform to the ImageContainer protocol to be able to receive the configured image. When to use Any? Any can represent an instance of any type at all, including function types: let arrayOfAny: [Any] = [ 0, "string", { (message: String) -> Void in print(message) } ] To me, the same rules apply to Any compared to AnyObject meaning that you should always seek to use concrete types instead. Any is more flexible by allowing you to cast instances of any type, making code harder to predict compared to using concrete types. When to use any? any is introduced in SE-335 and looks similar to Any and AnyObject but has a different purpose since you use it to indicate the use of an existential. The following example code demonstrates an image configurator using the sample code from previous examples in this article: struct ImageConfigurator { var imageContainer: any ImageContainer func configureImage(using url: URL) { // Note: This is not the way to efficiently download images // and is just used as a quick example. let image = UIImage(dаta: try! Data(contentsOf: url))! imageContainer.configureImage(image) } } let iconImageView = UIImageView() var configurator = ImageConfigurator(imageContainer: iconImageView) configurator.configureImage(using: URL(string: "https://picsum.photos/200/300")!) let image = iconImageView.image As you can see, we indicated the use of an existential ImageContainer by marking our imageContainer property with the any keyword. Marking a protocol using any will be enforced starting from Swift 6 as it will indicate the performance impact of using a protocol in this way. Existential types have significant limitations and performance implications and are more expensive than using concrete types since you can change them dynamically. The following code is an example of such change: let button = UIButton() configurator.imageContainer = button Our imageContainer property can represent any value conforming to our ImageContainer protocol and allows us to change it from an image view to a button. Dynamic memory is required to make this possible, taking away the possibility for the compiler to optimize this piece of code. Up until the introduction of the any keyword, there was no explicit indication to developers indicating this performance cost. Moving away from any In a way, you could argue any, Any, and AnyObject have something in common: use them with caution. You could rewrite the above code example by using generics and take away the need for dynamic memory: struct ImageConfigurator<Destination: ImageContainer> { var imageContainer: Destination } Being aware of the performance implications and knowing how to rewrite the code instead is an essential skill to own as a Swift developer. Conclusion Any, any, and AnyObject look similar but have important differences. In my opinion, it’s better to rewrite your code and take away the need to use any of these keywords. Doing so often results in more readable and predictable code.
The evolution of the Android security system or how the system is protected today How it all started The road to protecting Android has been thorny. At the end of 2021, Android March 16, 2022 Blog
14 Mobile App Trends in 2022 Since its inception, smartphones have become more and more popular every day. Technology is gaining February 26, 2022 Blog
How to Implement Complex Navigation in iOS Apps for iPhone Every app, unless it's a single-page app, must have navigation that allows users to move between February 14, 2022 Tutorials