简体   繁体   中英

How can I auto-sort an array in Swift by property type?

I'm trying to make a mutating function within a struct that will sort an array by its String property. That way, whenever an item is added to the array, it will sort itself alphabetically. I realize that what I have right now tries to make a change to the array within the own array's didSet method, but I'm not sure where to go with it right now. Currently I'm getting the error "Thread 1: EXC_BAD_ACCESS (code=2, address=...)". All the other code worked fine before trying to implement the sort method.

import Foundation

struct QuoteLibrary {
    var title : String
    var arrayOfSectionTitles: [String]
    var arrayOfSections : [Section] = [] {
        didSet {
            self.configureSections()
        }
    }

    mutating func configureSections() {
        // Sort alphabetically
        arrayOfSections.sort({ $0.title > $1.title })

        let numberOfSections = arrayOfSections.count - 1

        // Update the arrayOfSectionTitles whenever arrayOfSections is set
        var titleArray: [String] = []
        for k in 0...numberOfSections {
            titleArray.append(arrayOfSections[k].title)
        }
        arrayOfSectionTitles = titleArray

        // If a section has no quotes in it, it is removed
        for j in 0...numberOfSections {
            if arrayOfSections[j].arrayOfQuotes.count == 0 {
                arrayOfSections.removeAtIndex(j)
                return
            }
        }

    }
}

struct Section {
    var title : String, arrayOfQuotes:[Quote]
}

struct Quote {
    var section : String, text : String
}

enum QuoteStatus: Int {
    case Unchanged = 0
    case Changed = 1
    case Deleted = 2
    case Added = 3
}

You have a recursion problem. Every time you touch arrayOfSections , it'll call configureSections . That includes the changes configureSections is making to arrayOfSections , such as sorting or removing empty sections. You might just about get away with it with the removing of empty sections (because after the removal, the subsequent call doesn't remove anything, so won't alter the array and re-call the function), but sorting it pushed things over the edge.

You would probably be better off with a private array, and then a computed property that provided access to it, like this:

struct QuoteLibrary {
    private var _arrayOfSections: [Section] = []

    var title: String
    var arrayOfSectionTitles: [String] = []

    var arrayOfSections: [Section] {
        get { return _arrayOfSections }
        set(newArray) {
            _arrayOfSections = newArray.filter { !$0.arrayOfQuotes.isEmpty }
            _arrayOfSections.sort { $0.title > $1.title }
            arrayOfSectionTitles = _arrayOfSections.map { $0.title }
        }
    }

    init(title: String) { self.title = title }
}

Also you definitely want to look into Swift's capabilities for mapping, filtering of arrays etc. as an alternative to your for loops. Especially with your remove loop – removing elements from an array as you're iterating over it is really quite tricky, filter is a lot less error prone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM