Issue with UnsafePointer Uint8 in SQLite project in Swift
This should work:
let address = sqlite3_column_text(statement, 0)
let string = String.fromCString(UnsafePointer<CChar>(address))
Update for Swift 3 (Xcode 8), compare Swift 3: convert a null-terminated UnsafePointer<UInt8> to a string:
let string = String(cString: sqlite3_column_text(statement, 0))
Update:
sqlite3_column_text()
returns an implicitly unwrapped optional, and that is why you can pass it to String(cString:)
directly.
But according to Column methods, error and NULL handling #41, the return value can be null (in an out-of-memory situation, or if called with a NULL column type). Therefore it is safer to do
if let text = sqlite3_column_text(statement, 0) {
let string = String(cString: text)
// ...
} else {
// sqlite3_column_text() returned NULL
}
SwiftData (SQLite wrapper) broken with Swift 3.0
sqlite3_column_int(statement, index)
returns an Int32
and
sqlite3_column_int(statement, index) != 0
is a boolean value, so that makes no sense as the return value if
an (optional) AnyObject
is expected. You can wrap the integer into
a NSNumber
instead:
func getColumnValue(_ statement: OpaquePointer, index: Int32, type: String) -> AnyObject? {
let val = sqlite3_column_int(statement, index)
return NSNumber(value: val)
}
Another option would be
func getColumnValue(_ statement: OpaquePointer, index: Int32, type: String) -> AnyObject? {
return sqlite3_column_int(statement, index) as AnyObject
}
because in Swift 3, anything can be converted to AnyObject
.
The difference is that in the second solution, the object can only be
converted back to the original number type Int32
, but not toInt
or any other integer type.
For the other problems, see
- Issue with UnsafePointer<Uint8> in SQLite project in Swift
- Error in for loop CGFloat
Problem with SQLite.swift after migration to Swift 5
Till SQLite.swift
doesn't release any update with the fix you could try modify manually the SQLite/Foundation.swift
for fromDatatypeValue(_ dataValue: Blob)
function and the computed property datatypeValue
in this way:
public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
return Data(dataValue.bytes)
}
public var datatypeValue: Blob {
return withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in
return Blob(bytes: pointer.baseAddress!, length: count)
}
}
Swift 3: convert a null-terminated UnsafePointer UInt8 to a string
In Swift 3, String
has two initializers
public init(cString: UnsafePointer<CChar>)
public init(cString: UnsafePointer<UInt8>)
therefore it can be created from (null-terminated) sequences of both signed and unsigned characters. So
let s = String(cString: yourCharPointer)
should just work.
String
has another initializer
public init?(validatingUTF8 cString: UnsafePointer<CChar>)
which fails on ill-formed UTF-8 sequences instead of replacing them
by the replacement characters. This init method has no counterpart
taking unsigned characters.
Taking the existing implementations in CString.swift as examples, it is not too difficult to add this as an extension:
extension String {
public init?(validatingUTF8 cString: UnsafePointer<UInt8>) {
guard let (s, _) = String.decodeCString(cString, as: UTF8.self,
repairingInvalidCodeUnits: false) else {
return nil
}
self = s
}
}
and then
if let s = String(validatingUTF8: yourCharPointer) {
print(s)
} else {
print("invalid UTF-8")
}
also works with (null-terminated) sequences of both signed and unsigned characters.
Create UnsafeMutablePointer UInt8 in Swift 3
(DES is not secure and should not be used in new work; it has been superceed by AES)
Example fragment:
let cryptLength = size_t(data.count + kCCBlockSizeDES)
var cryptData = Data(repeating:0, count:cryptLength)
var numBytesEncrypted :size_t = 0
let keyLength = size_t(kCCKeySizeDES)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
ivData.withUnsafeBytes {ivBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(operation),
algoritm,
options,
keyBytes, keyLength,
ivBytes,
dataBytes, data.count,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}
}
}
Example from sunsetted documentation section:
AES encryption in CBC mode with a random IV (Swift 3+)
The iv is prefixed to the encrypted data
aesCBC128Encrypt
will create a random IV and prefixed to the encrypted code.aesCBC128Decrypt
will use the prefixed IV during decryption.
Inputs are the data and key are Data objects. If an encoded form such as Base64 if required convert to and/or from in the calling method.
The key should be exactly 128-bits (16-bytes), 192-bits (24-bytes) or 256-bits (32-bytes) in length. If another key size is used an error will be thrown.
PKCS#7 padding is set by default.
This example requires Common Crypto
It is necessary to have a bridging header to the project:
#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework
to the project.
This is example, not production code.
enum AESError: Error {
case KeyError((String, Int))
case IVError((String, Int))
case CryptorError((String, Int))
}
// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)
let status = cryptData.withUnsafeMutableBytes {ivBytes in
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
}
if (status != 0) {
throw AESError.IVError(("IV generation failed", Int(status)))
}
var numBytesEncrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
cryptBytes,
dataBytes, data.count,
cryptBytes+kCCBlockSizeAES128, cryptLength,
&numBytesEncrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.count = numBytesEncrypted + ivSize
}
else {
throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
}
return cryptData;
}
// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let clearLength = size_t(data.count - ivSize)
var clearData = Data(count:clearLength)
var numBytesDecrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
options,
keyBytes, keyLength,
dataBytes,
dataBytes+kCCBlockSizeAES128, clearLength,
cryptBytes, clearLength,
&numBytesDecrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
clearData.count = numBytesDecrypted
}
else {
throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
}
return clearData;
}
Example usage:
let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData: \(clearData as NSData)")
print("keyData: \(keyData as NSData)")
var cryptData :Data?
do {
cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
print("cryptData: \(cryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCEncrypt: \(status)")
}
let decryptData :Data?
do {
let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCDecrypt: \(status)")
}
Example Output:
clearData: <636c6561 72446174 61303132 33343536>
keyData: <6b657944 61746138 39303132 33343536>
cryptData: <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>
Notes:
One typical problem with CBC mode example code is that it leaves the creation and sharing of the random IV to the user. This example includes generation of the IV, prefixed the encrypted data and uses the prefixed IV during decryption. This frees the casual user from the details that are necessary for CBC mode.
For security the encrypted data also should have authentication, this example code does not provide that in order to be small and allow better interoperability for other platforms.
Also missing is key derivation of the key from a password, it is suggested that PBKDF2 be used is text passwords are used as keying material.
For robust production ready multi-platform encryption code see RNCryptor.
How to use SCNetworkReachability in Swift
(This answer was extended repeatedly due to changes in the Swift language, which made it a bit confusing. I have now rewritten it and removed everything which refers to Swift 1.x. The older code can
be found in the edit history if somebody needs it.)
This is how you would do it in Swift 2.0 (Xcode 7):
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else {
return false
}
var flags : SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
return (isReachable && !needsConnection)
}
Explanations:
As of Swift 1.2 (Xcode 6.3), imported C structs have a default initializer in Swift, which initializes all of the struct's fields to zero, so the socket address structure can be initialized with
var zeroAddress = sockaddr_in()
sizeofValue()
gives the size of this structure, this has
to be converted toUInt8
forsin_len
:zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
AF_INET
is anInt32
, this has to be converted to the correct type forsin_family
:zeroAddress.sin_family = sa_family_t(AF_INET)
withUnsafePointer(&zeroAddress) { ... }
passes the address of the
structure to the closure where it is used as argument forSCNetworkReachabilityCreateWithAddress()
. TheUnsafePointer($0)
conversion is needed because that function expects a pointer tosockaddr
, notsockaddr_in
.The value returned from
withUnsafePointer()
is the return value
fromSCNetworkReachabilityCreateWithAddress()
and that has the
typeSCNetworkReachability?
, i.e. it is an optional.
Theguard let
statement (a new feature in Swift 2.0) assigns the unwrapped value to thedefaultRouteReachability
variable if it is
notnil
. Otherwise theelse
block is executed and the function
returns.- As of Swift 2,
SCNetworkReachabilityCreateWithAddress()
returns
a managed object. You don't have to release it explicitly. As of Swift 2,
SCNetworkReachabilityFlags
conforms toOptionSetType
which has a set-like interface. You create an
empty flags variable withvar flags : SCNetworkReachabilityFlags = []
and check for flags with
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)The second parameter of
SCNetworkReachabilityGetFlags
has the typeUnsafeMutablePointer<SCNetworkReachabilityFlags>
, which means that you have to
pass the address of the flags variable.
Note also that registering a notifier callback is possible as of
Swift 2, compare Working with C APIs from Swift and Swift 2 - UnsafeMutablePointer<Void> to object.
Update for Swift 3/4:
Unsafe pointers cannot be simply be converted to a pointer of a
different type anymore (see - SE-0107 UnsafeRawPointer API). Here the updated code:
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
unexpectedly found nil while unwrapping an Optional value while reading from DS with fromCString
Another possible solution is this:
let unsafepointer=UnsafePointer<CChar>(sqlite3_column_text(statement, 2));
var sText = "unsafe text pointer is nil !";
if unsafepointer != nil{
if let text = String.fromCString(unsafepointer) as String?{
sText = text;
}
}
Creating custom sqlite functions in Swift alone
SQLite.swift provides a type-safe Swift interface for creating custom SQL functions (disclaimer: I wrote and maintain SQLite.swift). The current version bridges to Objective-C internally, though this is an implementation detail you can ignore. A future version will likely use Swift 2's function pointer API. And while you can use C function pointers in Swift 1.x with some @objc_block
and unsafeBitCast
, it's quite a bit worse to read and maintain.
The most basic way to create a cos
function:
import SQLite
import Darwin
// opens a database connection
let db = Database()
// defines a "cos" function on the connection
db.create(function: "cos", argc: 1, deterministic: true) { args in
if let x = args[0] as? Double {
return Darwin.cos(x)
}
return nil
}
println(db.scalar("SELECT cos(1.0)"))
// Optional(0.54030230586813977)
A more complex, safer example wherein SQLite.swift generates a type-safe interface to your database given a contract:
import SQLite
import Darwin
// opens a database connection
let db = Database()
// defines a "cos" function on the connection
let cos: Expression<Double> -> Expression<Double> = (
db.create(function: "cos", deterministic: true, Darwin.cos)
)
// builds a SQL expression for the column, "x"
let x = Expression<Double>("x")
// creates a query reference for the table, "table"
let table = db["table"]
// creates the table
db.create(table: table) { t in
t.column(x)
}
// CREATE TABLE "table" ("x" REAL)
// inserts a row where "x" is 1.0
table.insert(x <- 1.0)
// INSERT INTO "table" ("x") VALUES (1.0)
// executes the query
for row in db.select(cos(x)) {
println(row[cos(x)])
}
// SELECT "cos"("x") FROM "table"
Related Topics
How to Limit an iOS App Only to 4 Inch Screen Devices
I Get Conflicting Provisioning Settings Error When I Try to Archive to Submit an iOS App
Xcode 8/Swift 3: "Expression of Type Uiviewcontroller? Is Unused" Warning
Convert Uiimage to Nsdata and Convert Back to Uiimage in Swift
How to Make a Function Execute Every Second in Swift
How to Delete All Objects from My Persistent Store in Core Data
Swift - Downloading Video with Downloadtaskwithurl
Why Is Uiscrollview Leaving Space on Top and Does Not Scroll to the Bottom
How to Save an Array to .Plist in the App's Mainbundle in Swift
Googlemaps Basic iOS Demo App Crash - Unrecognized Selector Sent to Instance
Images Can't Contain Alpha Channels or Transparencies
Getting the Value of a Uitextfield as Keystrokes Are Entered
How to Set the Full Width of Separator in Uitableview
Disable Swipe Back Gesture in Swift
How to Localize the Images in Images.Xcassets
-[Nsnull Length]: Unrecognized Selector Sent to JSON Objects