Reputation: 65
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
}
Upvotes: 2
Views: 1979
Reputation: 40965
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.
Upvotes: 1