4 Replies
      Latest reply: Oct 28, 2016 3:17 AM by eskimo RSS
      vimipatel Level 2 Level 2 (30 points)

        What are the differences between :

         

        convenience init()

        required init()

        override init()

        init()

         

        I am getting error, where I have two init methods. convenience init() and init()

         

        Error is : 'self' used before super.init call


        I have write super.init(), then also no luck. Please let me know about above methods.

        • Re: Differences between init() methods
          Claude31 Level 5 Level 5 (1,565 points)

          convenience init is an init you define to pass some parameters.

           

          It must have a different signature than the override init() : usually, it is the parameter you want to pass to the init. But even if you have no parameter to pass, you should pass a dummy one to differentiate signature.

           

          Here is an example in my code

           

           

              override init(window: NSWindow!)
              {
                  super.init(window: window)
              }
          
              required init?(coder: (NSCoder!))
              {
                  super.init(coder: coder)
              }
          
              convenience init(dataType: DataType) {
               
                  self.init(windowNibName: "XXXXX")        
                  content = MyObject(dataType: dataType)  // Initialize the object model
              }
          

          Have a look here to understand all details :

           

          https : / / developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID222

          • Re: Differences between init() methods
            eskimo Apple Staff Apple Staff (7,005 points)

            Claude31 offered a very general answer, which is all we can do given the info you posted.  If you post a cut down example of the case you’re trying to cope with, we should be able to offer more specific advice.

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Differences between init() methods
              vimipatel Level 2 Level 2 (30 points)

              Here is my code snippet :

               

               

              class FileOutputStream : OutputStream {
              
                  fileprivate let filepath:URL
                  fileprivate let channel:DispatchIO!
              
                  convenience init?(filename:String) {
                  
                      let pathURL = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in:.userDomainMask).first!.appendingPathComponent(filename)
                      self.init(filepath:pathURL)
                  }
              
                  init?(filepath f:URL) {
                  
                      self.filepath = f
                  
                      /
                      if let cpath = (f.path).cString(using: String.Encoding.utf8) {
                      
                          let outputflag:Int32 = O_CREAT | O_WRONLY            
                          let mode:mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
                          self.channel = DispatchIO(type: DispatchIO.StreamType.stream, path:cpath, oflag:outputflag,mode: mode, queue: DispatchQueue.global(qos: DispatchQoS.QoSClass.background)) { (errcode:Int32) -> Void in
                          
                              if errcode != 0 {
                                  print("FileOutputStream: error creating io channel")
                              }
                          }
                      }
                      else {
                          self.channel = nil
                          return nil
                      }
                      super.init(url: self.filepath, append: true)!
                  }
              
                  func write(_ string: String) {
                  
                      if let dataString = string.data(using: String.Encoding.utf8) {
                      
                          dataString.withUnsafeBytes {(bytes: UnsafePointer<UInt8>) -> Void in
                          
                              var data = DispatchData.empty
                              data.append(bytes, count: dataString.count)
                          
                              self.channel.write(offset: 0, data: data, queue: DispatchQueue.global(qos:.background), ioHandler: { (complete: Bool, data: DispatchData?, errorCode: Int32) in
                              
                                  /
                                  if errorCode != 0 {
                                      print("FileOutputStream: error writing data to channel")
                                  }
                              })
                          }
                      }
                  }
              
                  deinit {
                  
                      self.channel.close(flags: DispatchIO.CloseFlags.stop)
                  }
              }
              

               

               

              @eskimo  and @Claude31 Please take a look on my snippet and give me more specification, if possible. Bacause everytime I confused between these four types of difinations of init()

                • Re: Differences between init() methods
                  eskimo Apple Staff Apple Staff (7,005 points)

                  In general the rules for how a subclass should override initialisers are well defined, as discussed in the doc that Claude31 referenced.  What’s weird here is OutputStream.  The Objective-C declaration lists three designated initialisers for NSOutputStream [1], none of which make sense to call super with from an arbitrary subclass, which is what you have to do.

                  The good news here is that the superclass initialiser that you call is more-or-less irrelevant.  When you subclass NSOutputStream, all the designated initialisers act as no-ops because the instance you get back is your subclass of the abstract NSOutputStream, which is not what you get back when you instantiate NSOutputStream normally.  Consider this:

                  let sConcrete = OutputStream(toMemory: ())
                  print(type(of:sConcrete))       // prints "__NSCFOutputStream"
                  print(sConcrete.superclass!)    // prints "NSOutputStream"
                  

                  This is the whole Cocoa class cluster concept in action; see the so-named section of the Concepts in Objective-C Programming doc.

                  In contrast, when you subclass NSOutputStream yourself, your subclass is directly layered on top of the abstract NSOutputStream.

                  class DummyOutputStream : OutputStream {
                  }
                  
                  let sDummy = DummyOutputStream(toMemory: ())
                  print(type(of:sDummy))          // prints "DummyOutputStream"
                  print(sDummy.superclass!)       // prints "NSOutputStream"
                  

                  Calling any method on that instance, even something as innocuous as -streamStatus, will trigger a failure.  For example, this:

                  print(sDummy.streamStatus)
                  

                  generates this:

                  2016-10-28 11:06:01.384 xxst[4901:363171] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -streamStatus only defined for abstract class.  Define -[xxst.DummyOutputStream streamStatus]!'
                  

                  This means that, when you override NSStream and NSOutputStream methods in your subclass, you must not call super.


                  If I were in your shoes I’d do two things:

                  • override all of the initialisers from OutputStream and Stream to make them private (so they don’t show up in code completion) and crashing (so if you find out if they’re called dynamically)

                  • add my own designated and convenience initialisers as required

                  Here’s an example:

                  struct Blob {
                      let squishiness: Int
                  }
                  
                  class BlobStream : OutputStream {
                  
                      required init(blob: Blob) {
                          self.blob = blob
                          super.init(toMemory: ())
                      }
                  
                      convenience init(squishiness: Int) {
                          self.init(blob: Blob(squishiness: squishiness))
                      }
                  
                      private init() {
                          fatalError()
                      }
                  
                      private override init(toBuffer buffer: UnsafeMutablePointer<UInt8>, capacity: Int) {
                          fatalError()
                      }
                  
                      private override init?(url: URL, append shouldAppend: Bool) {
                          fatalError()
                      }
                  
                      let blob: Blob
                  
                      … more code here…
                  }
                  

                  At this point you have to override and implement every NSStream and NSOutputStream that might be called by your code (or by any code you pass the stream to).


                  Obviously this is more than a little wacky, so please feel free to file a bug report describing your goạls, the issues you hit, and what you’d like to see improved.  I’d appreciate you posting your bug number, just for the record.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                  [1] Namely -initToMemory, -initToBuffer:capacity: and -initWithURL:append:.