I tried to implement CQRS pattern in swift ios app and I found weird behavior.
Core classes:
class Query<T> {}
class QueryHandler<TResult, TQuery:Query<TResult>> {
func execute(query: TQuery, callback: (result: TResult) -> Void ) {
}
}
Implementing classes:
class GetRandomStringsQuery: Query<[String]> {
internal var prefix:String
init(prefix: String) {
self.prefix = prefix
}
}
class GetRandomStringsQueryHandler: QueryHandler<[String], GetRandomStringsQuery> {
override func execute(query: GetRandomStringsQuery, callback: (result: [String]) -> Void) {
var result = [String]()
for var i = 0; i < 100; i++ {
result.append("[\(i)]: \(query.prefix)")
}
callback(result: result)
}
}
Example usage:
@IBAction func generateMemoryLeak(sender: AnyObject) {
let query = GetRandomStringsQuery(prefix: "leak leak leak :(")
let queryHandler = GetRandomStringsQueryHandler()
queryHandler.execute(query) { (result) -> Void in
print("total records: \(result.count)")
}
}
In callback we should get 100 elements in array. At runtime it seems like the reference is lost and value is unknown. iOS Developer Instruments detect memory leak.
Weid behvaior is that when we remove super class from GetRandomStringsQueryHandler and remove "override" modifier from execute function there will be no memory leak and app will work fine!
Could somebody explains this behavior? It's my mistake or swift issue?
I'm Using final verion of Xcode with swift 2.
Interesting question! I pasted your code into the playground and managed to reproduced the error you encountered. I tried to tweak the code but failed to get the generics to work. As an alternative, I end up rewriting the code using protocols to express the constraints.
Core protocols:
protocol QueryType {
typealias ResultType
}
protocol QueryHandler {
typealias Query: QueryType
func execute(query: Self.Query, callback: (result: Self.Query.ResultType) -> Void)
}
Conforming classes:
class GetRandomStringsQuery: QueryType {
typealias ResultType = [String]
internal var prefix:String
init(prefix: String) {
self.prefix = prefix
}
}
class GetRandomStringsQueryHandler: QueryHandler {
func execute(query: GetRandomStringsQuery, callback: (result: [String]) -> Void) {
var result = [String]()
for var i = 0; i < 100; i++ {
result.append("[\(i)]: \(query.prefix)")
}
callback(result: result)
}
}
Calling code:
let query = GetRandomStringsQuery(prefix: "leak leak leak :(")
let queryHandler = GetRandomStringsQueryHandler()
queryHandler.execute(query) { (result) -> Void in
print("total records: \(result.count)")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With