The Default Memberwise Initializers Headache

July 10, 2016

I ran into a problem recently on a Swift server-side project that uses Kitura. The problem though, can happen to anyone using Swift in a project. I was using an external framework that was imported through the Swift Package Manager. In attempting to use it, I tried to use a certain class, lets call it Bulbasaur, and I would continually get the following error:

Bulbasaur initializer is inaccessible due to internal protection level

The code causing this issue looked like this:

let myFirstPokemon = Bulbasaur(type:"Grass", maxHP: 20)

I checked the source code for this framework and did not see anything obviously wrong since the Bulbasaur struct was declared public. It didn’t make any sense why I wasn’t able to create a Bulbasaur instance using the default memberwise initializer. Which means an initializer created by the language behind the scenes for each property in the structure. At this point, the struct looked like this:

public struct Bulbasaur {

    public let type: String
    
    public let maxHP: Int
}

I tried many debugging techniques, like re-creating the struct right above the method I was working in, which did compile, but would cause other issues in the framework because it was a completly different struct. I edited the access control modifiers in the struct to make different combinations, then I made the struct a class, but none of these attempts were successful.

The Solution

Alas, I went home for the day and began work the next day with a clear mind. As you might expect, I figured out the issue within 30 minutes, making my problem seem silly, as hindsight will make you think. While I’m sure this is an issue many have run into, I found it suprisingly undocumented until I found this one StackOverlow post answer. Once I read the following, all became clear:

As with the default initializer above, if you want a public structure type to be initializable with a memberwise initializer when used in another module, you must provide a public memberwise initializer yourself as part of the type’s definition.

Sure enough, this was taken directly from Apple’s documentation in the section about default memberwise initializers. Although my struct was public and my properties were public, the code using the struct was in a different module, causing the default initializer to be internally protected by default. With this in mind, I made the appropriate addition:

public struct Bulbasaur {

    public let type: String
    
    public let maxHP: Int
    
    public init(type: String, maxHP: Int) {
        self.type = type
        self.maxHP = maxHP
    }
}

Of course, that resolved all my issues. Simply adding an initializer that seemed unnecessary allowed me to create my own instance of Bulbasaur with ease. While this issue was a headache, it is helping me learn the importance of documentation and knowing the intricacies of a language. This can be difficult with all the changes to Swift, including proposals about improving default memberwise initializers. Regardless, you know better, I know better, now onto the next issue 😫

Tweet submit to reddit

Recent Posts

  • Moving From iOS To Server-Side Swift
  • Types of Swift Error Handling
  • My NSHipster Reader Submission
  • Top 9 Storyboard Mistakes in Xcode
  • Best features in Xcode UI Testing