In each of the examples below, does blob.0 or text need to be copied? How do you know?
Setup
import SQLite3
private let static_destructor = unsafeBitCast(0, to: sqlite3_destructor_type.self)
private let transient_destructor = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
Examples
bind_blob
func bind_blob(_ stmt: OpaquePointer, _ blob: (UnsafeRawPointer, Int32)) {
sqlite3_bind_blob(stmt, 1, blob.0, blob.1, transient_destructor)
}
bind_blobs
func bind_blobs(_ stmt: OpaquePointer, _ blobs: [(UnsafeRawPointer, Int32)]) {
for (index, blob) in blobs.enumerated() {
sqlite3_bind_blob(stmt, Int32(index+1), blob.0, blob.1, transient_destructor)
}
}
bind_text
func bind_text(_ stmt: OpaquePointer, _ text: String) {
sqlite3_bind_text(stmt, 1, text, -1, transient_destructor)
}
bind_texts
func bind_texts(_ stmt: OpaquePointer, _ texts: [String]) {
for (index, text) in texts.enumerated() {
sqlite3_bind_text(stmt, Int32(index+1), text, -1, transient_destructor)
}
}
Ie, should I use static_destructor instead of transient_destructor in any of the examples?
Related question: When to use SQLITE_TRANSIENT vs SQLITE_STATIC?
In your bind_text and bind_texts functions, you need to use the transient destructor. When you pass a Swift String to a C function as a const char * argument, Swift does not guarantee that the pointer will remain valid after the C function returns. The Calling Functions With Pointer Parameters article says this:
The pointer you pass to the function is only guaranteed to be valid for the duration of the function call. Do not persist the pointer and access it after the function has returned.
In your bind_blob and bind_blobs functions, it depends where the UnsafeRawPointer comes from and when you execute the SQL statement. If you're getting the pointer using any sort of Swift withUnsafeWhatever function, then the pointer is not valid after the withUnsafeWhatever function returns. For example, the withUnsafeBytes(of:_:) documentation says this:
The buffer pointer argument is valid only for the duration of the closure’s execution.
If you bind your blob, execute the statement, and then no longer use the binding, then you can use the static destructor. This is okay with the static destructor:
let data: Data = ...
data.withUnsafeBytes { rawBuffer in
if let pointer = rawBuffer.baseAddress {
bind_blob(statement, (pointer, rawBuffer.count))
execute(statement)
// No more use of statement unless the parameter is rebound.
}
}
But this is not okay with the static destructor:
let data: Data = ...
data.withUnsafeBytes { rawBuffer in
if let pointer = rawBuffer.baseAddress {
bind_blob(statement, (pointer, rawBuffer.count))
}
}
execute(statement)
Related
I previously used this code in Swift 4.2 to generate an id:
public static func generateId() throws -> UInt32 {
let data: Data = try random(bytes: 4)
let value: UInt32 = data.withUnsafeBytes { $0.pointee } // deprecated warning!
return value // + some other stuff
}
withUnsafeBytes is deprecated on Swift 5.0. How can I solve this?
In Swift 5 the withUnsafeBytes() method of Data calls the closure with an (untyped) UnsafeRawBufferPointer, and you can load() the value from the raw memory:
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
(compare How to use Data.withUnsafeBytes in a well-defined manner? in the Swift forum). Note that this requires that the memory is aligned on a 4-byte boundary. For alternatives see round trip Swift number types to/from Data.
Note also that as of Swift 4.2 you can create a random 32-bit integer simply using the new Random API:
let randomId = UInt32.random(in: .min ... .max)
On Xcode 10.2, Swift 5, using $0.load(as:) didn't work for me, both when reading from the pointer or writing to it.
Instead, using $0.baseAddress?.assumingMemoryBound(to:) seems to work well.
Example reading from the pointer buffer (code is unrelated to the question):
var reachability: SCNetworkReachability?
data.withUnsafeBytes { ptr in
guard let bytes = ptr.baseAddress?.assumingMemoryBound(to: Int8.self) else {
return
}
reachability = SCNetworkReachabilityCreateWithName(nil, bytes)
}
Example writing to the buffer pointer (code is unrelated to the question):
try outputData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) in
let status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
passphrase,
passphrase.utf8.count,
salt,
salt.utf8.count,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
rounds,
outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
kCCKeySizeAES256)
guard status == kCCSuccess else {
throw Error.keyDerivationError
}
}
The code from the question would look like:
let value = data.withUnsafeBytes {
$0.baseAddress?.assumingMemoryBound(to: UInt32.self)
}
In cases where the 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(…) warning persists, it seems like the compiler can get confused when the closure has only one line. Making the closure have two or more lines might remove the ambiguity.
One more way to fix this warning to use bindMemory(to:).
var rawKey = Data(count: rawKeyLength)
let status = rawKey.withUnsafeMutableBytes { rawBytes -> Int32 in
guard let rawBytes = rawBytes.bindMemory(to: UInt8.self).baseAddress else {
return Int32(kCCMemoryFailure)
}
return CCSymmetricKeyUnwrap(alg, ivBytes, iv.count, keyBytes, key.count, wrappedKeyBytes, wrappedKey.count, rawBytes, &rawKeyLength)
}
I got this error as I was trying to figure out a compression stream tutorial. To get it to work, I added a step of converting the raw buffer pointer to a UnsafePointer
Original code from a tutorial I was working on.
--> where input: Data
--> where stream: compression_stream
//Method that shows the deprecation alert
return input.withUnsafeBytes { (srcPointer: UnsafePointer<UInt8>) in
//holder
var output = Data()
//Source and destination buffers
stream.src_ptr = srcPointer //UnsafePointer<UInt8>
stream.src_size = input.count
… etc.
}
Code with a conversion to make the above code work with a valid method
return input.withUnsafeBytes { bufferPtr in
//holder
var output = Data()
//Get the Raw pointer at the initial position of the UnsafeRawBuffer
let base: UnsafeRawPointer? = bufferPtr.baseAddress
//Unwrap (Can be combined with above, but kept it separate for clarity)
guard let srcPointer = base else {
return output
}
//Bind the memory to the type
let count = bufferPtr.count
let typedPointer: UnsafePointer<UInt8> = srcPointer.bindMemory(to: UInt8.self, capacity: count)
// Jump back into the original method
stream.src_ptr = typedPointer //UnsafePointer<UInt8>
}
I'm trying to create a somewhat generic function to sort file URLs based the value of an attribute
My goal is to:
1) Pass the URL and some parameters (Including the type) to a function.
which will then loop through the file's attributes
2) Add the matching file attribute and the URL to an array of tuples
3) Sort the tuples by the value of the found attribute
4) Return the sorted array and display the items in sorted order
I believe that I need to pass the type of the attribute into the sorting function so I'm able to set it in the tuple since I'm unable to sort with "Any" but I'm unsure of how to do that
I'm okay with passing anything into the sorting function and constructing or deconstructing the value I need in the sorting function since that will be predefined depending upon what action is selected by the user
//Initial implementation to be later tied to IBActions and simplified
func sortFiles(sortByKeyString : String, fileURLArray : [URL]) -> [URL]
{
switch sortByKeyString {
case "date-created-DESC":
let fileAttributeKeyString : String = "creationDate"
let isSortOrderDesc = true
let objectTypeString : String = NSDate.className()
let sortedFileURLArray = sortFileArrayByType(fileAttributeKeyString: fileAttributeKeyString, fileURLArray: fileURLArray, type: objectTypeString, isSortOrderDesc : isSortOrderDesc)
return sortedFileURLArray
default:
return fileURLArray
}
}
//Generic function to get a files attributes from a URL by requested
type
func sortFileArrayByType(fileAttributeKeyString : String, fileURLArray : [URL], type: String, isSortOrderDesc : Bool) -> [URL] {
let fileManager = FileManager.default
let attributeToLookFor : FileAttributeKey = FileAttributeKey.init(rawValue: fileAttributeKeyString)
var tupleArrayWithURLandAttribute : [(url: URL, attribute: *Any*)]? = nil
for url in fileURLArray {
do {
let attributes = try fileManager.attributesOfItem(atPath: url.path)
for (key, value) in attributes {
if key.rawValue == fileAttributeKeyString {
tupleArrayWithURLandAttribute?.append((url: url, attribute: value))
}
}
let sortedTupleArrayWithURLandAttribute = tupleArrayWithURLandAttribute?.sorted(by: { $0.attribute < $1.attribute)})
// Need to Sort dictionary into array
return sortedTupleArrayWithURLandAttribute
} catch {
return fileURLArray
}
}
}
First read Metatype Type in the The Swift Programming Language. Once read continue with the answer.
From that you have learnt that you can declare a function parameter's type to be the type of types (you are allowed to go crosseyed), AKA metatype, and can therefore pass a type to a function. Combine that with generics and Swift's type inference and you could declare your function as:
func sortFileArrayByType<T>(fileAttributeKeyString : String,
attributeType : T.Type,
fileURLArray : [URL]
) -> [(url: URL, attribute: T)]
where T : Comparable
This adds the parameter attributeType whose type is the metatype of T where T will be inferred. For example the metatype String.self could be passed and T will be inferred to be String.
The where clause constrains T so that only types which are Comparable are allowed, this is required to enable the function to do sorting. File attributes can be Date, String and NSNumber valued; unfortunately the latter does not conform to Comparable so you need to add an extension to make it, the following will suffice:
extension NSNumber : Comparable
{
public static func <(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedAscending }
public static func ==(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedSame }
}
Within the body of the function you need to declare your array of tuples to have attributes of type T:
var tupleArrayWithURLandAttribute : [(url: URL, attribute: T)] = []
and when you add entries you need to cast the value returned by attributesOfItem to be T:
tupleArrayWithURLandAttribute.append((url: url, attribute: value as! T))
Note the use of as! here, you must match the attribute name and the type of its value correctly in the function call or you will get a runtime abort. Handling this as a soft error, if needed, is left as an exercise.
There are a number of typos etc. in the code you posted, they are left for you to fix, having done that your function should work. A call might look like:
let ans = sortFileArrayByType2(fileAttributeKeyString: "NSFileCreationDate",
attributeType: Date.self,
fileURLArray: urlArray)
and the type of ans in this case will be [(url: URL, attribute: Date)]
HTH
So I think I know what you're getting at and this is what I've come up with:
func checkType<T>(_ type: T.Type) {
if type.self == String.self {
print("It's a string!")
} else if type.self == Int.self {
print("It's an int!")
} else {
print("It's something else...")
}
}
And then you can call this either by passing in a type directly to it, or by getting the type of a variable and passing that in as follows:
checkType(String.self) // prints "It's a string!"
let number: Int = 1
checkType(type(of: number)) // prints "It's an int!"
Hope this helps!
What you're looking for here is a way to sort a sequence of URLs by a URLResourceKey (and specifically by the URLResourceValues property related to that key). Unfortunately, URLResourceValues aren't mapped to URLResourceKey in a useful way. But we can fix that with an extension:
extension URLResourceValues {
static func key<T>(for keyPath: KeyPath<Self, T>) -> URLResourceKey {
switch keyPath {
case \Self.creationDate: return .creationDateKey
// ... Other keys ...
default: fatalError()
}
}
}
And it would be very useful to get a value for a URLResourceValues keyPath:
extension URL {
func resourceValue<T>(for keyPath: KeyPath<URLResourceValues, T?>) throws -> T? {
return try resourceValues(forKeys: Set([URLResourceValues.key(for: keyPath)]))[keyPath: keyPath]
}
}
With that, we can build a sorting method based on URLResourceValues (assuming nil is less than other values; you could replace that with throwing for non-existent values):
extension Sequence where Element == URL {
func sorted<T>(by keyPath: KeyPath<URLResourceValues, T?>) throws -> [URL]
where ResourceType: Comparable {
return try self
.sorted { (lhs, rhs) in
guard let lhsValue = try lhs.resourceValue(for: keyPath)
else { return true }
guard let rhsValue = try rhs.resourceValue(for: keyPath)
else { return false }
return lhsValue < rhsValue
}
}
}
And finally, that can be used by passing a keypath, based on URLResourceValues:
let sortedFiles = try files.sorted(by: \.creationDate)
I'm trying to debug some SQLite queries in my code using tracing to just log to the console everything that happens, but there seems to be almost no information on it - a Google search for "sqlite3_trace_v2 swift" only returns two pages of results, none of which were helpful except the above link. Using the following code, I was able to get it to the point where it at least runs the trace callback:
func traceSQL (database: OpaquePointer?) {
var pointer: OpaquePointer?
func traceCallback (mask: UInt32, pointer: UnsafeMutableRawPointer?, query: UnsafeMutableRawPointer?, result: UnsafeMutableRawPointer?) -> Int32 {
print("SQLite Trace:")
if let query = query?.load(as: UnsafePointer<Int8>.self) {
print(String(cString: query))
} else {
print("Could not load query.")
}
if let result = result?.load(as: UnsafePointer<Int8>.self) {
print(String(cString: result))
} else {
print("Could not load result.")
}
return 0
}
sqlite3_trace_v2(database, 15, traceCallback as #convention(c) (UInt32, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Int32, &pointer)
}
but I can't figure out what to do with the output of the function - currently, it just prints out a string of unreadable characters, and my previous attempts didn't even manage that. I suspect at least part of the problem is that I don't really know how to work with UnsafeMutableRawPointer in Swift (something else that seems to be lacking in available information).
tl;dr: How do I log tracing results from SQLite?
The main error in your code is that you derefence the raw pointers
passed to the callback instead of reinterpreting (casting) them.
Also the meaning of those pointers is different for the different
events.
Here is an example how to trace the various events and how to convert
the raw pointers to the "correct" types, using a literal closure
as callback. The comments explaining the meaning of the p and x
argument are taken from SQL Trace Event Codes.
let traceMask = SQLITE_TRACE_STMT|SQLITE_TRACE_PROFILE|SQLITE_TRACE_ROW|SQLITE_TRACE_CLOSE
sqlite3_trace_v2(database, UInt32(traceMask), { (reason, context, p, x) -> Int32 in
switch Int32(reason) {
case SQLITE_TRACE_STMT:
// The P argument is a pointer to the prepared statement.
// The X argument is a pointer to a string which is the unexpanded SQL text
guard
let pStmt = OpaquePointer(p),
let cSql = x?.assumingMemoryBound(to: CChar.self)
else {
return 0
}
let sql = String(cString: cSql) // The unexpanded SQL text
let expandedSql = String(cString: sqlite3_expanded_sql(pStmt)) // The expanded SQL text
print("SQLITE_TRACE_STMT:", expandedSql)
case SQLITE_TRACE_PROFILE:
// The P argument is a pointer to the prepared statement and the X argument points
// to a 64-bit integer which is the estimated of the number of nanosecond that the
// prepared statement took to run.
guard
let pStmt = OpaquePointer(p),
let duration = x?.load(as: UInt64.self)
else {
return 0
}
let milliSeconds = Double(duration)/Double(NSEC_PER_MSEC)
let sql = String(cString: sqlite3_sql(pStmt)) // The unexpanded SQL text
print("SQLITE_TRACE_PROFILE:", milliSeconds, "ms for statement:", sql)
case SQLITE_TRACE_ROW:
// The P argument is a pointer to the prepared statement and the X argument is unused.
guard
let pStmt = OpaquePointer(p)
else {
return 0
}
print("SQLITE_TRACE_ROW")
case SQLITE_TRACE_CLOSE:
// The P argument is a pointer to the database connection object and the X argument is unused.
guard
let database = OpaquePointer(p)
else {
return 0
}
print("SQLITE_TRACE_CLOSE")
default:
break
}
return 0
}, nil)
Of course you can restrict the trace mode to the events that you
are interesting in, e.g.
let traceMask = SQLITE_TRACE_STMT
to trace only prepared statements.
I'm trying to get used to generics (never used them in objc) and want to write a toy function that takes an object of any type () and returns the first and last element. Hypothetically, I'd only use this on an array or a string - I keep getting an error that has no subscript members. I totally understand that the error message is telling me swift has no clue that T may potentially hold a type that does have subscripts - I just want to know how to get around this.
func firstAndLastFromCollection<T>(a:T?) {
var count: Int = 0
for item in a as! [AnyObject] {
count++
}
if count>1 {
var first = a?[0]
var last = a?[count-1]
return (first, last)
}
return something else here
}
Do I need to typecast somewhere here (which would kind of defeat the purpose here, as I'd need to downcast as either a string or an array, adding code and lessening how generic this func is)?
If you want to return the first and the last element then it's probably safe assuming the input param is an array of some kind of type.
So you can implement your function this way
func firstAndLast<T>(list:[T]) -> (first:T, last:T)? {
guard let first = list.first, last = list.last else { return nil }
return (first, last)
}
The function does return a tuple of 2 element, both have the same type of the generic element of the input array.
The returned tuple is an option because if the array is empty then nil is returned.
Examples
let nums = firstAndLast([1,2,3,4])
let words = firstAndLast(["One", "Two", "Three"])
As you can verify the type of the generic element into the array becomes the type of the elements inside the tuple.
In the example above nums is inferred to be (Int, Int)? and words (Words, Words)?
More examples
let emptyList: [String] = []
firstAndLast(emptyList) // nil
Extension
Finally you can also write this code as an extension of Array.
extension Array {
var firstAndLast: (first:Element, last:Element)? {
guard let first = self.first, last = self.last else { return nil }
return (first, last)
}
}
Now you can write
let aCoupleOfShows = ["Breaking Bad", "Better Call Saul", "Mr Robot"].firstAndLast
Again, if you check the type of the constant aCoupleOfShows you'll see that is a (first: String, last: String)?. Swift automatically did infer the correct type.
Last example
In the comments you said you wanted the first and last chars of a String. here it is the code if you use the extension above
if let chars = Array("Hello world".characters).firstAndLast {
print("First char is \(chars.first), last char is \(chars.last) ")
}
//>> First char is H, last char is d
If we are talking about collections, let's use the CollectionType:
func firstAndLastFromCollection<T: CollectionType>(a: T) -> (T.Generator.Element, T.Generator.Element)? {
guard !a.isEmpty else {
return nil
}
return (a.first!, a.lazy.reverse().first!)
}
print(firstAndLastFromCollection(["a", "b", "c"])) // ("a", "c")
print(firstAndLastFromCollection("abc".characters)) // ("a", "c")
print(firstAndLastFromCollection(0..<200)) // (0, 199)
print(firstAndLastFromCollection([] as [String])) // nil
If you specify your generic type to also conform to bidirectional index:
func firstAndLastFromCollection<T: CollectionType where T.Index : BidirectionalIndexType>(...) -> ...
then you can call last directly:
return (a.first!, a.last!)
If we decide to implement it using a category, we don't need generics at all:
extension CollectionType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.lazy.reverse().first!)
}
}
extension CollectionType where Index: BidirectionalIndexType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.last!)
}
}
print("abc".characters.firstAndLast())
Swift is a protocol oriented language. Usually you will find yourself extend protocols more than extending classes or structs.
I am attempting to use Parse to call up some variables and put them into a struct that is already initialized. The calling of the variables is happening smoothly and the data is available, but the inputing of the class into the function is not happening.
'unit' is a struct that has the name, hp, attack, etc. variables contained within it.
Is it not possible to pass along an instance of a struct and modify it's values like this? It would save me a lot of copy-pasting code to do it this way.
Thanks for your help!
func fetchStats(name: String, inout nameOfClass: unit) {
var unitStatArray = []
let query = PFQuery(className: "UnitStats")
query.whereKey("name", equalTo: name)
query.findObjectsInBackgroundWithBlock{(objects:[PFObject]?, error: NSError?)->Void in
if (error == nil && objects != nil){ unitStatArray = objects! }
nameOfClass.name = "\(unitStatArray[0].objectForKey("name")!)"
print("class name is \(nameOfClass.name)")
print("cannon name is \(cannon.name)")
nameOfClass.hitPoints = unitStatArray[0].objectForKey("hitPoints") as! Double
nameOfClass.hitPointsMax = unitStatArray[0].objectForKey("hitPointsMax") as! Double
nameOfClass.attack = unitStatArray[0].objectForKey("attack") as! Double
nameOfClass.defense = unitStatArray[0].objectForKey("defense") as! Double
nameOfClass.rangedAttack = unitStatArray[0].objectForKey("rangedAttack") as! Double
nameOfClass.rangedDefense = unitStatArray[0].objectForKey("rangedDefense") as! Double
nameOfClass.cost = unitStatArray[0].objectForKey("cost") as! Int
}
}
fetchStats("3-inch Ordnance Rifle", nameOfClass: &cannon)
This is an attempt to explain what I had in mind when writing my comment above.
Because there's an asynchronous call to findObjectsInBackgroundWithBlock, the inout won't help you here. The idea is to add a callback fetched like this:
func fetchStats(name: String, var nameOfClass: unit, fetched: unit -> ()) {
// your code as above
query.findObjectsInBackgroundWithBlock {
// your code as above plus the following statement:
fetched(nameOfClass)
}
}
This can be called with
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
nameOfClass = newNameOfClass
}
(all of this code has not been tested)
The point is that you understand that your code is asynchronous (I know, I'm repeating myself). After you have called fetchStats you don't know when the callback (here: the assignment nameOfClass = newNameOfClass) will be executed. You cannot assume the assignment has been done after fetchStats has returned.
So whatever you need to do with the changed nameOfClass: the corresponding statements must go into the callback:
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
// do whatever you want with the received newNameOfClass
}
Hope this helps.