I am attempting to migrate a Swift 2.2 iOS app that I did not write to Swift 3. There are a bunch of functions that use Realm to obtain models and return them in an array. These all worked in Swift 2.x, but are generating the error below in Swift 3. I have also included the associated function definition.
/SubmissionDataManager.swift:184:16: Cannot convert return expression of type 'LazyFilterBidirectionalCollection>' to return type '[EntryModel]'
func validateSubmission(_ submissionId: Int) -> ([EntryModel]) {
let realm = try! Realm()
let submissionModel = realm.objects(SubmissionModel.self).filter({ $0.id == submissionId }).first!
let entryModels = submissionModel.entryModels
// Check for all entry details field which are mandatory and are empty and not hidden
let emptyEntryModels = entryModels.filter({ $0.entryDetailArray.filter({ $0.entryDetailValue.isEmpty && $0.isMandatory && !($0.isHidden) }).count > 0 })
return emptyEntryModels
}
I'm not sure what the actual problem is, or how I would go about fixing it. Any suggestions appreciated.
Swift is deferring the creation of an array for efficiency's sake. Instead of giving you an Array, it is providing you with a LazyFilterBidirectionalCollection
which is a lazy Collection
wrapper that includes the elements of an underlying collection that satisfy a predicate. In your case, it is the Realm elements that satisfy the closure you passed to filter
. Lazy means that the values are pulled from Realm as you access them instead of all at once. A Collection
is a protocol that conforms to Sequence
and Indexable
. A Sequence
is a type that provides sequential, iterated access to its elements. So, at its most basic level, LazyFilterBidirectionalCollection
is a sequence.
There is an initializer for Array
that converts a Sequence
into an array:
init<S : Sequence where S.Iterator.Element == Element>(_ s: S)
Since you need to return a real array
replace:
return emptyEntryModels
with:
return Array(emptyEntryModels)
That will make a proper array from the LazyFilterBidirectionalCollection
.
Other examples of using this Array
initializer to convert a sequence into an array:
let digits = Array(0...9) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let odds = Array(stride(from: 1, through: 9, by: 2)) // [1, 3, 5, 7, 9]