Convenience initialization of UINavigationController subclass makes subclass constant init twice

I have subclasses of UINavigationController and UITableViewController.

To initialize subclasses I decided to use some convenience init methods that call some designated initializer of the superclass. Also, each subclass has some let constant:

  • Alamofire upload image with multipart/form-data
  • Custom UITableViewCell in edit mode does not move my UILabels
  • VoiceOver: force an accessibility element to be selected after a screen transition
  • Loading/Downloading image from URL on Swift
  • How to convert Objective-C TOCropViewController delegate method in Swift?
  • Can UILongPressGestureRecognizer be used together with touch events like touchesMoved?
  • let someValue: SomeClass = SomeClass()
    

    Each class is successfully initialized by calling its newly created convenience init method.

    The problem is that the let constant is initialized TWICE in UINavigationController subclass.

    import UIKit
    import PlaygroundSupport
    
    final class Navigation: UINavigationController {
        convenience init(anyObject: Any) {
            self.init(rootViewController: UIViewController())
        }
        let service = Constant("Constant Initialization -> Navigation")
    }
    
    final class Table: UITableViewController {
        convenience init(anyObject: Any) {
            self.init(style: .plain)
        }
        let service = Constant("Constant Initialization -> Table")
    }
    
    class Constant: NSObject {
        init(_ string: String) {
            super.init()
            debugPrint(string)
        }
    }
    
    Navigation(anyObject: NSNull())
    Table(anyObject: NSNull())
    

    Are we allowed to use convenience init like above? Why?

    Why is the convenience init behavior is different in these two cases?

    Checked with: Version 8.2 beta (8C30a), Version 8.2 (8C38), Version 8.2.1 (8C1002)

    P.S. Playground log of the code above:

    "Constant Initialization -> Navigation"
    "Constant Initialization -> Navigation"
    "Constant Initialization -> Table"
    

    Solutions Collect From Internet About “Convenience initialization of UINavigationController subclass makes subclass constant init twice”

    So this seems to be weirdly “expected behavior” with Swift. The reason it’s happening is due to the constant initialized property service. Namely, this post summarizes the issue your seeing pretty well: blog post

    Essentially, the Obj-C underlying super classes are leaking memory and your service property is initialized twice because of this pattern of Obj-C initialization:

    - (id)init {
      self = [super init];
      if (self) {
        self = [[self.class alloc] initWithNibName:nil bundle:nil];
      }
      return self;
    }
    

    A simple solution to avoid this is the following pattern:

    import UIKit
    
    final class NavigationController: UINavigationController {
        var service: ObjectTest?
    
        convenience init() {
            self.init(rootViewController: UIViewController())
            self.service = ObjectTest("init nav")
        }
    }
    class ObjectTest: NSObject{
        init(_ string: String) {
            super.init()
            print(string)
        }
    }
    

    All that’s changing from your implementation is initializing the service only after your class itself is initialized.

    Another solution, though, is to use the designated initializer for the superclass your initializing. Meaning that you don’t use a convenience initializer which would employ the above Obj-C initialization pattern.