SinaSB
SinaSB

Reputation: 175

Cannot assign through subscript to Swift String

I have a class that contains a name, an image, a dashed form of the name, and the length of the name. For example, I could have "dog", an image of a dog, "---", and name length 3.

I just want to set name and pic for each object and have dashName and nameLength set automatically.

class Answer {
    var name = "name"
    var image: UIImage?
    var dashName = "name"
    var nameLength = 0

    init(){

        var a = 0
        nameLength = name.characters.count

        while a <= nameLength {
            if (name[a] == " ") {dashName[a] = " "}
            else {dashName[a] = "-"}
            a += 1
        }
    }
}

The problem is the error that says: "cannot assign through subscript: subscript is get-only" and another error that says: "subscript is unavailable: cannot subscript String with an Int"

Upvotes: 4

Views: 4031

Answers (3)

Josh Homann
Josh Homann

Reputation: 16347

Because String's subscript operator is get-only, use map method instead, like:

class Answer {
    var name = "name"
    var image: UIImage?
    var dashName = "name"
    var nameLength = 0
    
    init(){
        dashName = String(name.map {$0 == " " ? " " : "-"})
    }
}

Upvotes: 2

Top-Master
Top-Master

Reputation: 8826

As mentioned before, Swift's String class is what other languages call a StringBuilder class, and for performance reasons, Swift does NOT provide setting character by index; If you don't care about performance a simple solution could be:

public static func replace(_ string: String, at index: Int, with value: String) {
    let start = string.index(string.startIndex, offsetBy: index)
    let end = string.index(start, offsetBy: 1)
    string.replaceSubrange(start..<end, with: value)
}

Or as an extension:

extension String {
    public func charAt(_ index: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: index)];
    }

    public mutating func setCharAt(_ index: Int, _ new: Character) {
        self.setCharAt(index, String(new))
    }

    public mutating func setCharAt(_ index: Int, _ new: String) {
        let i = self.index(self.startIndex, offsetBy: index)
        self.replaceSubrange(i...i, with: new)
    }
}

Note how above needs to call index(...) method to convert integer to actual-index!? It seems, Swift implements String like a linked-list, where append(...) is really fast, but even finding the index (without doing anything with it) is a linear-time operation (and gets slower based on concatenation count).

Upvotes: 1

XmasRights
XmasRights

Reputation: 1509

The subscript operator for String is get-only, which means you can only read from a string using it, and have to use something else to write to a mutable String.

You can solve this issue, and clean up the code by using a map function on name

Swift 4

class Answer {
    var name = "name"
    var image: UIImage?
    var dashName = "name"
    var nameLength = 0

    init()
    {
        nameLength = name.count
        dashName = name.map { $0 == " " ? " " : "-" }.joined()
    }
}

Swift 3

class Answer {
    var name = "name"
    var image: UIImage?
    var dashName = "name"
    var nameLength = 0

    init()
    {
        nameLength = name.characters.count
        dashName = name.characters.map { $0 == " " ? String(" ") : String("-") }.joined()
    }
}

Upvotes: 0

Related Questions