2

I've created the following classes:

class Person {
    private var name: String = ""

    private init(name thisName: String) {
        name = thisName
    }

    class func CreatePerson(#type: String, name: String) -> Person! {

        if type == "girl" {
            return Female(name: name)
        }
        else if type == "boy" {
            return Male(name: name)
        }

        return nil
    }

    func PrintName() {
        println(name)
    }
}

class Male: Person {

    override init(name thisName: String) {
        super.init(name: thisName)
    }

    deinit {
        println("Deleting a male.")
    }
}

class Female: Person {

    deinit {
        println("Deleting a female.")
    }
}

class AnotherClass {

    var secondPeopleArray: [Person]! = nil

    func DoSomething(#people: [Person]) {

        secondPeopleArray = [Person]()
        for person: Person! in people {
            let male: Male! = person as? Male
            if male != nil {
                secondPeopleArray.append(male)
            }
        }
    }
}

As you can see, I've created a class called Person with two subclasses (Male and Female). I've also created a class (AnotherClass) that takes an array of Person classes and builds a new array of Male classes. As you can see, the

I've created the following code that builds the Person class arrays and calls the Another class function DoSomething. DoSomething allocates the array and filters the people array and appends only the Male classes to the secondPeopleArray member.

    var firstPeopleArray = [Person]()

    var firstPerson: Person = Person.CreatePerson(type: "boy", name: "Bill")
    var secondPerson: Person = Person.CreatePerson(type: "boy", name: "Ted")
    var thirdPerson: Person = Person.CreatePerson(type: "girl", name: "Nancy")
    var fourthPerson: Person = Person.CreatePerson(type: "girl", name: "Diane")

    firstPeopleArray.append(firstPerson)
    firstPeopleArray.append(secondPerson)
    firstPeopleArray.append(thirdPerson)
    firstPeopleArray.append(fourthPerson)

    var anotherClass: AnotherClass = AnotherClass()
    anotherClass.DoSomething(people: firstPeopleArray)
    anotherClass.DoSomething(people: firstPeopleArray)

    for person in firstPeopleArray {
        person.PrintName()
    }

As you can see, the DoSomething function is called twice. This is intentional. The first time DoSomething is called, the array in the AnotherClass is created properly. The second time the DoSomething function is called, a new array is allocated (which deallocates the old array). The strange thing is the members of the array are also deallocated, which results in firstPeopleArray to have deallocated references as members of the array. Accessing the member in the for loop results in a crash.

I've found the following line is the culprit:

for person: Person! in people {

Changing this line to the following fixes the issue:

for person: Person in people {

The question is, Why? Why would the unwrapping symbol (the !) affect the references in a way in which having the symbol there results in the system thinking it needs to deallocate the member of the array when the array is deallocated and the reference clearly is used in the firstPeopleArray?

BCM
  • 21
  • 2
  • 1
    Not a solution, but a small comment; this code `let male: Male! = person as? Male` is not good. When you declare an implicitly unwrapped optional type, you are declaring a variable that you expect to have something in it when you call it, but don't want to initialize. You shouldn't check for `nil` on implicitly unwrapped optionals. Better is to use `if let male = person as? Male {...}`. The code in the parentheses is only going to get executed when `person` is `Male`. – vrwim Mar 20 '15 at 12:02
  • I copied all of your code into a playground. The `for person in firstPeopleArray` loop doesn't cause a crash. Which Swift version do you use? – ctietze Mar 20 '15 at 12:03
  • @ctietze Try with Xcode6.2 with OS X Command Line Tool template. Playground is not suitable for testing this kind of problem. see: http://stackoverflow.com/q/24363384/3804019 – rintaro Mar 20 '15 at 12:31
  • ctietze: You are quite correct. You do not see the issue in a playground. You will only see the issue if you run the code as part of an application. – BCM Mar 20 '15 at 12:48
  • You are right, @BCM, and I was able to reproduce this. I first thought that maybe this was a hidden feature: like Ruby's bang indicating a mutating action, maybe your for-in loop worked like a mutable stack from which you pop elements. Doesn't make sense though, and doesn't seem to misbehave outside of a loop. I suggest you file a bug with Apple. – ctietze Mar 26 '15 at 10:52
  • @ctietze: Thanks for the advice. For those interested, I posed this question at: https://devforums.apple.com/message/1118374#1118374 – BCM Mar 27 '15 at 12:08

0 Answers0