Search code examples
ioscocoa-touchapple-documentation

If Apple's documentation says not to subclass a class, does this mean we should treat the class as a singleton and have only one?


In Apple's documentation there are "Subclassing Notes" which sometimes may say to not subclass a specific class. For example HKHealthStore has this verbiage in its documentation: "Like many classes in HealthKit, the HKHealthStore class should not be subclassed.".

However, in a tutorial that compiles, we created one instance of the HKHealthStore class and used it for reference to the HealthStore functions. For example:

let currentHealthStore = HKHealthStore()

if HKHealthStore.isHealthDataAvailable(){
            //The following is for if HealthKit is supported in this device
            print("Yes, this iPhone 6 Plus supports Health Information")

            let typesToRead = dataToRead()
            let typesToWrite = dataToWrite()
            currentHealthStore.requestAuthorization(toShare: typesToWrite as? Set<HKSampleType>, read: typesToRead as? Set<HKObjectType>, completion: { (success, error) -> Void in

                if success{

                    // We will update UI to preview data we read.
                    DispatchQueue.main.async(execute: { () -> Void in

                        self.loadView()
                    })

                }
                else{

                    print("User didn't allow HealthKit to access these read/write data types")
                }

            })
        } else {
            let alertController = UIAlertController(title: "Warning", message: "HealthKit is not available in your device!", preferredStyle: UIAlertControllerStyle.alert)

            alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.cancel, handler: nil))

            self.present(alertController, animated: true, completion: nil)
        }

Solution

  • Comments have already addressed this pretty well, but to pull it together...


    Subclassing is when you create a new class with a superclass:

    class MyHealthStore: HKHealthStore { /* DON'T DO THIS */ }
    
    let store = MyHealthStore()
    

    For the class you're working with, the guidance from Apple is to avoid subclassing. They don't guarantee any behavior regarding what happens if you override methods of the superclass, etc.... so just don't do it.

    This documentation-based guidance is equivalent to declaring a class as final in Swift. However, HKHealthStore and most other Apple framework classes are defined in ObjC, which doesn't have anything like a final keyword, so such classes are limited to just saying "please don't subclass" in documentation.


    A singleton is when a class has a single shared instance at run time. There are a number of Apple framework classes that do this, typically exposing access to the shared instance via a class method or class property: UIApplication.shared, PHImageManager.default(), ProcessInfo.processInfo (formerly NSProcessInfo.processInfo()), etc.

    In general, there's no conflict between subclassing and singletons. You're welcome, for example, to create a UIApplication subclass, in which case (assuming your app is set up correctly), UIApplication.shared will return the shared instance of your subclass.

    HealthKit is a little bit odd in this regard. HKHealthStore is not a singleton class — it doesn't have a class method for accessing a shared instance, and you can create distinct instances of it using the default initializer (i.e. calling HKHealthStore()). However, all of those instances you create still manage the same underlying shared resource.