Swift slow on object creation and setValue:forKey: -
i accessing local mysql database in swift code translated objective c. in objective c performs fast, in swift 10 15 times slower depending on count of records.
i using generics create data transfer objects. sql select method has signature:
func sqlselect<t: nsobject>(select: string) -> [t]?
first fetched 20.000 records mysql database , returned empty array of ts. time needed 0.3 seconds, not fast acceptable.
then created 20.000 t instances in above function , appended them local swift array, fast: 0.1 sec.
now creating 5 nsnumbers , 9 strings fetched mysql data slow: 1.2 sec. 280.000 object creations (14 * 20.000 = 280.000). additional 1.4 seconds used setting properties of each t instance setvalue:forkey:
the same code in objective c , in xojo (aka realbasic) fast: less 1 second compared more 3 seconds.
what options make swift code faster?
first edit – added source code:
func sqlselect<t: nsobject>(select: string) -> [t]? { ... // error handling omitted var statement = select.cstringusingencoding(nsutf8stringencoding)! var err = mysql_real_query(mysql, statement, strlen(statement)) ... // error handling omitted var mysql_result: unsafemutablepointer<mysql_res> = mysql_store_result(mysql) ... // error handling omitted var mysql_fields: unsafemutablepointer<mysql_field> = mysql_fetch_fields(mysql_result) ... // error handling omitted var names = [string]() var types = [uint32]() var columncount = mysql_num_fields(mysql_result) i: int in 0...columncount - 1 { names.append(string.fromcstring(mysql_fields[i].name)!) types.append(mysql_fields[i].type.value) } var records = [t]() var recordcount = int(mysql_num_rows(mysql_result)) records.reservecapacity(recordcount - 1) r in 0...recordcount - 1 { var row = mysql_fetch_row(mysql_result) var record = t() c: int in 0...columncount - 1 { var value: anyobject? if row[c] == nil { value = nil; } else { switch types[c] { case mysql_type_tiny.value, mysql_type_short.value, mysql_type_int24.value, mysql_type_long.value: value = nsnumber(int: atoi(row[c])) case mysql_type_float.value: value = nsnumber(float: strtof(row[c], nil)) ... // other data types omitted case mysql_type_tiny_blob.value, mysql_type_blob.value, mysql_type_medium_blob.value, mysql_type_long_blob.value, mysql_type_bit.value, mysql_type_set.value, mysql_type_enum.value, mysql_type_geometry.value, mysql_type_var_string.value, mysql_type_string.value: if mysql_fields[c].charsetnr == 63 { value = nsdata(bytes: row[c], length: int(strlen(row[c]))) } else { value = string.fromcstring(row[c])! } case mysql_type_null.value: value = nil default: value = nil } record.setvalue(value, forkey: names[c]) } } records.append(record) } return records }
second edit: results running code in instruments
it shows approximately 40% of time spent in:
-[nsobject(nskeyvaluecoding) setvalue:forkey:]
and deeper in function these 3 functions:
@objc swift._nscontiguousstring.getcharacters (swift._nscontiguousstring)(swift.unsafemutablepointer<swift.uint16>, range : c._swiftnsrange) -> () _swift_retain_(swift::heapobject*) _swift_release_(swift::heapobject*)
the second biggest time use in:
swift.array.append <a>(inout [a])(a) -> ()
so solution keep access database in objective c code.
Comments
Post a Comment