Search code examples
iosswiftdelegatesprivate

Delegate methods not called if implementing class is marked private?


Here's a short snippet of Swift code that works fine (where "fine" is defined as "Parsing!" being printed a whole bunch in response to calling the class method Parse.parse):

import Foundation

class Parse {
  class func parse(stream: NSInputStream) {
    return Parser().parse(stream)
  }

  class Parser: NSObject, NSXMLParserDelegate {
    func parse(stream: NSInputStream) {
      let XMLParser = NSXMLParser(stream: stream)
      let delegate = XMLParserDelegate()
      XMLParser.delegate = delegate
      XMLParser.parse()
    }

    class XMLParserDelegate: NSObject, NSXMLParserDelegate {
      func parser(
        parser: NSXMLParser,
        didStartElement elementName: String,
        namespaceURI: String?,
        qualifiedName qName: String?,
        attributes attributeDict: [NSObject : AnyObject])
      {
        NSLog("Parsing!")
      }
    }
  }
}

The problem comes when I attempt to use Swift's visibility features. In particular, I do not want to make the Parser class visible to other files (because there is no reason for it to be visible). If I declare it via private class Parser … however, the code ceases to work! parser:didStartElement:namespaceURI:qualifiedName:attributes: is no longer called!

This all seems bizarre to me and unlike how it would work in any other language. As such, I feel like one of the following two things must be true:

  1. Swift's system for namespacing is, at best, weird. More plainly, it just seems broken to me.

  2. Swift is fine and I am just doing something very silly! If that's the case, then great! Please let me know what it is!

Thanks for the help, everyone!


Edit: Here's a slightly trimmed-down version. As before, the code works fine until the Parser class is marked private:

import Foundation

class Parse {
  class func parse(stream: NSInputStream) {
    return Parser().parse(stream)
  }
}

class Parser: NSObject, NSXMLParserDelegate {
  func parse(stream: NSInputStream) {
    let XMLParser = NSXMLParser(stream: stream)
    XMLParser.delegate = self
    XMLParser.parse()
  }

  func parser(
    parser: NSXMLParser,
    didStartElement elementName: String,
    namespaceURI: String?,
    qualifiedName qName: String?,
    attributes attributeDict: [NSObject : AnyObject])
  {
    NSLog("Parsing!")
  }
}

Solution

  • As per the investigation done by MartinR, this appears to be a bug (or something like it) that was introduced in Swift 1.2. Presumably this behavior is not intentional as I'm unaware of any other (reasonable, statically typed) language where marking a class as private can silently break your code at runtime. I'll follow up with Apple and see what they think of all this!