2

The code below fails to compile at the last line: "Could not find an overload for '+=' that accepts the supplied arguments."

How do I fix the code without changing the type for items?

class Test {
    var items:String[]?

    func process() {
        if (self.items == nil) {
            self.items = String[]()
        }

        for i in 1...5 {
            var item =  String(i)
            self.items! += item
        }
    }
}

4 Answers 4

1

Create it lazily:

class Test {
  @lazy var items = String[]()
  ...
}
Sign up to request clarification or add additional context in comments.

Comments

1

The following will keep items as an optional array while maintaining the general flow:

class Test {
    var items : String[]?

    func process() {
        var items = self.items ? self.items! : String[]()

        for i in 1...5 {
            var item =  String(i)
            items += item;
        }

        self.items = items
    }
}

3 Comments

Aren't arrays copied on assignment? This results in two copies every time process() is called (except for the first time when the empty array is created).
They're lazily copied on assignment (they're not really copied until you change their size) but then again, they're also copied when you append items, so you're really copying the array 5 times every time through, no matter how you do it.
Well, not really "no matter how" you could minimize it by creating a single array of 5 strings and then appending that to the existing items array, that would only copy the array once per execution.
1

I have not figured out a way to append to an optional array. I don't believe that is possible. You can achieve a similar effect to what your code is attempting to do by doing this:

class Test {
    @lazy var items = [String]()

    func process() {
        for i in 1...5 {
            var item =  String(i)
            self.items.append(item)
        }
    }
}

Note: I already submitted a bug to Apple about this issue

5 Comments

I would like to instantiate items lazily, right before adding the first element.
And if one doesn't want to create the array until later, declare it with @lazy.
@Boon, with GoZoner's suggestion, you are achieving exactly that
With GoZoner's method, items is not Optional though right? So looks like there is no way to achieve lazy instantiation if we have an Optional Array?
@Boon I don't believe so, no
0

Update

In the version of Swift provided with Xcode 6 Beta 5, the bug is fixed and the code runs normally (after adaptation, of course), here's the new code:

class Test {
    var items:[String]?

    func process() {
        if (self.items == nil) {
            self.items = [String]()
        }

        for i in 1...5 {
            var item = String(i)
            self.items!.append(item)
        }
    }
}

Old Answer

I have found that the result of unwrapping is a constant, and a constant can't be mutated. Thus the error "Could not find an overload for '+=' that accepts the supplied arguments." since the operator '+=' is defined as:

@assignment func +=<A : ArrayType>(inout lhs: A, rhs: A._Buffer.Element)

So as solution you can either use @lazy attribute (as suggested by GoZoner and seen in drewag's answer) or David's method of creating a temporary variable.

Method 1 (@lazy):

Taken from drewag's answer

class Test {
    @lazy var items = String[]()

    func process() {
        for i in 1...5 {
            var item =  String(i)
            self.items.append(item)
        }
    }
}

Method 2 (temporary variable):

Taken from David's answer

class Test {
    var items : String[]?

    func process() {
        var items = self.items ? self.items! : String[]()

        for i in 1...5 {
            var item =  String(i)
            items += item;
        }

        self.items = items
    }
}

6 Comments

Thanks. How do you show via code that unwrapping is a constant?
Also, if the result of unwrapping is a constant, why would David's unwrapping work?
@Boon the only way to prove that unwrapping is a constant, is by trying the operations on a constant which will give the same error. Ex. let items = String[]; items += "a"
@Boon David's unwrapping works because he is unwrapping into a variable (var items) and as items is not a constant he can do all the normal operations
Thanks @Ziad - what's the difference between String[]? vs [String]?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.