-
Re: Differences between init() methods
Claude31 Oct 27, 2016 12:17 AM (in response to vimipatel)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 Oct 27, 2016 2:50 AM (in response to vimipatel)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/Hardwarelet myEmail = "eskimo" + "1" + "@apple.com"
-
Re: Differences between init() methods
vimipatel Oct 27, 2016 3:55 AM (in response to vimipatel)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 Oct 28, 2016 3:17 AM (in response to vimipatel)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
andStream
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/Hardwarelet myEmail = "eskimo" + "1" + "@apple.com"
[1] Namely
-initToMemory
,-initToBuffer:capacity:
and-initWithURL:append:
.
-