Swift 3 - Isolate a function - swift3

I need a function, which can only be called once, and you have to wait until the next one can be executed
private func receive(){
var inputBuffer = Array<UInt8>(repeating: 0, count: BUFFER_MAX);
let bytesRead = self.inputStream.read(&inputBuffer, maxLength: BUFFER_MAX);
if(bytesRead > 0){
let string = convertToString(byteArray: inputBuffer, length: bytesRead);
// Call if previous is finished
CommandHandler.convert(string);
}
}
I have tested something like this:
var dispQueue = DispatchQueue(label: "commandConvert")
...
private func convert(){
dispQueue.sync {
...
}
}
but this doesn't work

I just had this issue the other day.
You can solve this using a callback or a Dispatch Group. Here is the Dispatch Group solution:
class test {
let myDispatchGroup = DispatchGroup()
func receive () {
myDispatchGroup.enter()
var inputBuffer = Array<UInt8>(repeating: 0, count: BUFFER_MAX);
let bytesRead = self.inputStream.read(&inputBuffer, maxLength: BUFFER_MAX);
if(bytesRead > 0){
let string = convertToString(byteArray: inputBuffer, length: bytesRead);
myDispatchGroup.leave()
}
myDispatchGroup.notify(queue: DispatchQueue.main) {
// Call if previous is finished
CommandHandler.convert(string);
}
}

Related

Swift receives data from device by BLE

I have a device that transmits by BLE a message composed in this way: [STX]A1[ETX]
This device use a software written in C++ and 3rd character is a boolean!
Now, I would receive this message by iOS using swift. Other incoming message it received correctly, but this one not.
This is a method in C++ that trasmits:
isModeOn = (byte)data[1] == 1 ? true : false;
//Send message by BLE (by Serial)
Serial3.write(STX);
Serial3.write(GF);
Serial3.write(isModeOn);
Serial3.write(ETX);
This is my method in swift that receives:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print(#function)
var receivedMessage: String
if characteristic.uuid == BLE_RX_UUID {
receivedMessage = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)! as String
processMessage(receivedMessage: "\(receivedMessage as String)")
}
}
Can anyone help me?
UPDATE!
I found this approach:
//Lettura fecilitata dei NSData
struct DataReader {
var data: Data
var offset: Int = 0
mutating func read() -> UInt8 {
let result = data[offset]
offset += MemoryLayout<UInt8>.size
return result
}
mutating func read2() -> UInt16 {
let subdata = data.subdata(in: offset..<offset+MemoryLayout<UInt16>.size)
let result: UInt16 = subdata.withUnsafeBytes {(bytes: UnsafePointer<UInt16>) in
bytes.pointee.littleEndian
}
offset += MemoryLayout<UInt16>.size
return result
}
}
with this I can received easely my data
var reader = MessageHelper.DataReader.init(data: receivedMessage, offset: 0)
for _ in 1...reader.data.count {
let value = reader.read()
if value == STX {
incomingMessage = ""
} else if value == ETX {
print(#function, incomingMessage)
commandSelector(message: incomingMessage)
} else {
if value == 0x01 {
incomingMessage += "1"
} else if value == 0x00 {
incomingMessage += "0"
} else {
incomingMessage += "\(Character(UnicodeScalar(value)))"
}
}
}
OK! And If I need to send same message
sendMessage(message: String("\(COMMAND)\(Character(UnicodeScalar(UInt8(1))))"), withResponde: true)
I have to convert UInt8(1) in UnicodeScalar and then Character, and that's it!

iOS Swift 3 app rejected by App Store because of app crash in IPV6 network

My app was rejected by App Store because it crashed in IPV6 network. This happened to me a second time. I have already updated my code to support for IPV6 network and two builds are moved successfully in that code.
But now again they raised this same issue, they said this problem only occurs on Wi-Fi network. Here is my tried code:
internal class Reachability
{
class func isConnectedToNetwork() -> Bool
{
var zeroAddress = sockaddr_in6()
zeroAddress.sin6_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin6_family = sa_family_t(AF_INET6)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, "www.google.com")
}
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
}
Can you try this please it's working for me fine with 3g,4g and wifi network also work. the old one is not support to connectivity in mobile network.
class func isConnectedToNetwork() -> Bool
{
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
// zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0))
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
internal class ReachabilityCheck
{
class func isConnectedToNetwork() -> Bool
{
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress)
{
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false
{
return false
}
// Working for Cellular and WIFI
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
let ret = (isReachable && !needsConnection)
return ret
}
}

How to read a timecode track with AVAsset and Swift 3?

I'd like to read the time value of a timecode track. There is an
excellent documentation from Apple (see Technical Note 2310)
but it's written in Objective C.
I have translated the core logic to Swift 3. It works exactly as the
ObjC version, which means that a CMSampleBuffer from a timecode
track is read and converted to a CMBlockBuffer. It fails when I
create the data pointer CMBlockBufferGetDataPointer (in the
timecodeFrame() func), which means, that the raw data is always
giving me 0 frames. So it boils down to the question, how do I
handle the raw data correctly?
import Foundation
import AVFoundation
import CoreMedia
let movie = URL(fileURLWithPath: "videoWithTimecodeTrack.mov")
let asset = AVAsset(url: movie)
asset.loadValuesAsynchronously(forKeys: ["tracks"]) {
var error: NSError?
guard asset.statusOfValue(forKey: "tracks", error: &error) == AVKeyValueStatus.loaded
else { if let error = error { return print(error) } }
readStartTimecode(asset: asset)
}
func readStartTimecode(ofAsset asset: AVAsset) {
let timecodeTracks = asset.tracks(withMediaType: AVMediaTypeTimecode)
guard let timecodeTrack = timecodeTracks.first,
let assetReader = try? AVAssetReader(asset: asset) else { return }
let readerOutput = AVAssetReaderTrackOutput(track: timecodeTrack, outputSettings: nil)
assetReader.add(readerOutput)
guard assetReader.startReading() else { return }
while let sampleBuffer = readerOutput.copyNextSampleBuffer() {
if let frame = timecodeFrame(sampleBuffer: sampleBuffer) {
print("timecodeFrame: \(frame)")
}
}
}
func timecodeFrame(sampleBuffer: CMSampleBuffer) -> UInt32? {
guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer),
let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer)
else { return nil }
var rawData: UnsafeMutablePointer<Int8>? = nil
var length: Int = 0
var totalLength: Int = 0
let status = CMBlockBufferGetDataPointer(blockBuffer, 0, &length, &totalLength, &rawData)
guard status == kCMBlockBufferNoErr,
let frameRead = rawData?.pointee
else { return nil }
let type = CMFormatDescriptionGetMediaSubType(formatDescription)
if type == kCMTimeCodeFormatType_TimeCode32 {
let frame = UInt32(frameRead)
let bigFrame = CFSwapInt32BigToHost(frame)
print("kCMTimeCodeFormatType_TimeCode32: \(bigFrame)")
}
if type == kCMTimeCodeFormatType_TimeCode64 {
print("kCMTimeCodeFormatType_TimeCode64")
// todo
}
return nil
}
Edit: the Objective C version of the data pointer retrieval looks like this:
size_t length = 0;
size_t totalLength = 0;
char *rawData = NULL;
CMBlockBufferGetDataPointer(blockBuffer, 0, &length, &totalLength, &rawData);
if (status == kCMBlockBufferNoErr) {
int32_t *frameNumberRead = (int32_t *)rawData;
(int)Endian32_Swap(*frameNumberRead)]
}
The solution is to not convert the Int8 data like UInt32(rawData.pointee) but to access the UnsafeMutablePointer<Int8> pointer's memory as a different type (temporarily). This would look like this:
if let frames = rawData?.withMemoryRebound(to: UInt32.self, capacity: 1, { CFSwapInt32BigToHost($0.pointee) }) {
return frames
}
The full function would look like this:
func timecodeFrame(sampleBuffer: CMSampleBuffer) -> UInt32? {
guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer),
let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer)
else { return nil }
var rawData: UnsafeMutablePointer<Int8>? = nil
var length: Int = 0
var totalLength: Int = 0
let status = CMBlockBufferGetDataPointer(blockBuffer, 0, &length, &totalLength, &rawData)
guard status == kCMBlockBufferNoErr else { return nil }
let type = CMFormatDescriptionGetMediaSubType(formatDescription)
if type == kCMTimeCodeFormatType_TimeCode32 {
if let frames = rawData?.withMemoryRebound(to: UInt32.self, capacity: 1, { CFSwapInt32BigToHost($0.pointee) }) {
return frames
}
}
if type == kCMTimeCodeFormatType_TimeCode64 {
if let frames = rawData?.withMemoryRebound(to: UInt64.self, capacity: 1, { CFSwapInt64BigToHost($0.pointee) }) {
return UInt32(frames)
}
}
return nil
}
I hope this is useful to others who want to read the start timecode of a video's timecode track.

'self' used before super.init call in swift 3.0

I have sub class of OutputStream. In that I have two init() methods one have prefix word convenience.
Here is my code :
class FileOutputStream : OutputStream
{
fileprivate let filepath:URL
fileprivate let channel:DispatchIO!
convenience init?(filename:String) {
let pathURL = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in:.userDomainMask).first!.appendingPathComponent(filename)
self.init(filepath:pathURL)
}
init?(filepath f:URL) {
self.filepath = f
//if let path = f.path,
if let cpath = (f.path).cString(using: String.Encoding.utf8) {
let outputflag:Int32 = O_CREAT | O_WRONLY // create, write-only
let mode:mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH // permissions: u+rw, g+r, o+r
self.channel = DispatchIO(type: DispatchIO.StreamType.stream, path:cpath, oflag:outputflag,mode: mode, queue: DispatchQueue.global(qos: DispatchQoS.QoSClass.background)) { (errcode:Int32) -> Void in
if errcode != 0 {
print("FileOutputStream: error creating io channel")
}
}
}
else {
self.channel = nil
return nil
}
}
func write(_ string: String) {
if let dataString = string.data(using: String.Encoding.utf8) {
dataString.withUnsafeBytes {(bytes: UnsafePointer<UInt8>) -> Void in
var data = DispatchData.empty
data.append(bytes, count: dataString.count)
self.channel.write(offset: 0, data: data, queue: DispatchQueue.global(qos:.background), ioHandler: { (complete: Bool, data: DispatchData?, errorCode: Int32) in
//handle progress reporting here
if errorCode != 0 {
print("FileOutputStream: error writing data to channel")
}
})
}
}
}
deinit {
self.channel.close(flags: DispatchIO.CloseFlags.stop)
}
}
I am getting error
'self' used before super.init call
I have tried by writing
super.init()
in both method, at start of methods
at end of methods
only in second method
only in first method.
But still getting error. If anyone know, please help me.
Use super.init(url: f, append: false/true) at the end of your init?(filepath f:URL) method .
Your intializer must call designated intializer of super class..Call any of these init methods that is available in OutputStream class...
public init(toMemory: ())
public init(toBuffer buffer: UnsafeMutablePointer<UInt8>, capacity: Int)
#available(iOS 4.0, *)
public init?(url: URL, append shouldAppend: Bool)

How do I pass a callback function to sqlite3_exec in swift?

How do I pass a callback function to sqlite3_exec in Swift?
sqlite_str = sqlite_str + "\(sqlite_property_str))";
var str:NSString = sqlite_str;
var sqlite:COpaquePointer = share().sqlite3_db;
var errmsg:UnsafePointer<Int8> = nil
let rc = sqlite3_exec(sqlite, str.cStringUsingEncoding(NSUTF8StringEncoding), <#callback: CFunctionPointer<((UnsafePointer<()>, Int32, UnsafePointer<UnsafePointer<Int8>>, UnsafePointer<UnsafePointer<Int8>>) -> Int32)>#>, <#UnsafePointer<()>#>, <#errmsg: UnsafePointer<UnsafePointer<Int8>>#>)
Swift 2.2 provides two options for implementing the sqlite3_exec callback function: (1) a global, non-instance func procedure or (2) a non-capturing literal {} closure.
The sqlite.org's "SQLite in 5 minutes or less" example is implemented in a Swift Xcode7 project here.
Readable typealias
typealias sqlite3 = COpaquePointer
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
typealias CCharPointer = UnsafeMutablePointer<CChar>
typealias CVoidPointer = UnsafeMutablePointer<Void>
Callback Approach
func callback(
resultVoidPointer: CVoidPointer, // void *NotUsed
columnCount: CInt, // int argc
values: CCharHandle, // char **argv
columns: CCharHandle // char **azColName
) -> CInt {
for i in 0 ..< Int(columnCount) {
guard let value = String.fromCString(values[i])
else { continue }
guard let column = String.fromCString(columns[i])
else { continue }
print("\(column) = \(value)")
}
return 0 // status ok
}
func sqlQueryCallbackBasic(argc: Int, argv: [String]) -> Int {
var db: sqlite3 = nil
var zErrMsg:CCharPointer = nil
var rc: Int32 = 0 // result code
if argc != 3 {
print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0]))
return 1
}
rc = sqlite3_open(argv[1], &db)
if rc != 0 {
print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "" )
sqlite3_close(db)
return 1
}
rc = sqlite3_exec(db, argv[2], callback, nil, &zErrMsg)
if rc != SQLITE_OK {
print("ERROR: sqlite3_exec " + String.fromCString(zErrMsg)! ?? "")
sqlite3_free(zErrMsg)
}
sqlite3_close(db)
return 0
}
Closure Approach
func sqlQueryClosureBasic(argc argc: Int, argv: [String]) -> Int {
var db: sqlite3 = nil
var zErrMsg:CCharPointer = nil
var rc: Int32 = 0
if argc != 3 {
print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0]))
return 1
}
rc = sqlite3_open(argv[1], &db)
if rc != 0 {
print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "" )
sqlite3_close(db)
return 1
}
rc = sqlite3_exec(
db, // database
argv[2], // statement
{ // callback: non-capturing closure
resultVoidPointer, columnCount, values, columns in
for i in 0 ..< Int(columnCount) {
guard let value = String.fromCString(values[i])
else { continue }
guard let column = String.fromCString(columns[i])
else { continue }
print("\(column) = \(value)")
}
return 0
},
nil,
&zErrMsg
)
if rc != SQLITE_OK {
let errorMsg = String.fromCString(zErrMsg)! ?? ""
print("ERROR: sqlite3_exec \(errorMsg)")
sqlite3_free(zErrMsg)
}
sqlite3_close(db)
return 0
}
This is (currently) not possible. The Xcode 6 beta 4 release notes state:
However, you cannot call a C function pointer or convert a closure to
C function pointer type.
As a workaround, you could put sqlite3_exec together with its callback into a
C wrapper function and call that from Swift.
I wanted to provide an update to #l --marc l answer for Swift 3 and Linux which helped me get up and running. Thank you #l --marc l !
Callback Approach
func callback(
resultVoidPointer: UnsafeMutablePointer<Void>?, // void *NotUsed
columnCount: Int32, // int argc
values:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, // char **argv
columns:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? // char **azColName
) -> CInt {
var dic: [String:String] = [:]
for i in 0 ..< Int(columnCount) {
guard let value = values?[i]
else { continue }
guard let column = columns?[i]
else { continue }
let strCol = String(cString:column)
let strVal = String(cString:value)
dic[strCol] = strVal
//print("\(strCol) = \(strVal)")
}
resultSet.append(dic)
return 0 // status ok
}
func sqlQueryCallbackBasic(dbStr:String, query:String) -> Int {
var db: OpaquePointer?
var zErrMsg:UnsafeMutablePointer<Int8>?
var rc: Int32 = 0 // result code
rc = sqlite3_open(dbStr, &db)
if rc != 0 {
print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "" )
sqlite3_close(db)
return 1
}
rc = sqlite3_exec(db, query, callback, nil, &zErrMsg)
if rc != SQLITE_OK {
let errorMsg = zErrMsg
print("ERROR: sqlite3_exec \(errorMsg)")
sqlite3_free(zErrMsg)
}
sqlite3_close(db)
return 0
}
Closure Approach
func sqlQueryClosureBasic(dbStr:String, query:String) -> Int {
var db: OpaquePointer?
var zErrMsg:UnsafeMutablePointer<Int8>?
var rc: Int32 = 0
rc = sqlite3_open(dbStr, &db)
if rc != 0 {
print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "" )
sqlite3_close(db)
return 1
}
rc = sqlite3_exec(
db, // database
query, // statement
{ // callback: non-capturing closure
resultVoidPointer, columnCount, values, columns in
var dic: [String:String] = [:]
for i in 0 ..< Int(columnCount) {
guard let value = values?[i]
else { continue }
guard let column = columns?[i]
else { continue }
let strCol = String(cString:column)
let strVal = String(cString:value)
dic[strCol] = strVal
//print("\(strCol) = \(strVal)")
}
resultSet.append(dic)
return 0
},
nil,
&zErrMsg
)
if rc != SQLITE_OK {
let errorMsg = zErrMsg
print("ERROR: sqlite3_exec \(errorMsg)")
sqlite3_free(zErrMsg)
}
sqlite3_close(db)
return 0
}
Test
import Glibc
var resultSet: [[String: String]] = [[:]]
//sqlQueryClosureBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee")
sqlQueryCallbackBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee")
for row in resultSet {
for (col, val) in row {
print("\(col): \(val)")
}
}
The first parameter of that C function (the third argument of sqlite3_exec) is the thing you passed into the fourth argument of sqlite3_exec. Therefore, it's possible to pass a Swift closure into sqlite3_exec.
// Define a Type for later loading in the C function
typealias RowHandler = (
Int32,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Void
// The Swift closure to pass into sqlite3_exec
var rowHandler: RowHandler = { count, names, values in
// Do anything you want
}
let state = withUnsafeMutablePointer(to: &rowHandler) { rowHandlerPointer in
return sqlite3_exec(
connection,
"SOME SQLITE STATEMENT",
{ rowHandlerRawPointer, columnCount, values, columns in
// Load the pointer as the Type of the closure
let rowHandler = rowHandlerRawPointer!.load(as: RowHandler.self)
// Use it!
rowHandler(columnCount, columns, values)
},
rowHandlerPointer, // This will become rowHandlerRawPointer in the C function
nil
)
}
Because RowHandler is a Swift closure type, we can make it a parameter of a wrapper method:
class SQLiteDatabase {
// Define a closure type for later loading in the C function
typealias RowHandler = (
Int32,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Void
var connection: OpaquePointer?
// Other methods...
func execute(_ statement: String, receiveRow: #escaping RowHandler) -> Int32 {
// The Swift closure to pass into sqlite3_exec
var rowHandler = receiveRow
let state = withUnsafeMutablePointer(to: &rowHandler) { rowHandlerPointer in
return sqlite3_exec(
connection,
statement,
{ rowHandlerRawPointer, columnCount, values, columns in
// Load the pointer as the Type of the closure
let rowHandler = rowHandlerRawPointer!.load(as: RowHandler.self)
// Use it!
rowHandler(columnCount, columns, values)
},
rowHandlerPointer, // This will become rowHandlerRawPointer in the C function
nil
)
}
return state
}
}
Usage:
func result(database: SQLiteDatabase) -> [[String: String]] {
var rows = [[String: String]]()
_ = database.execute("SOME STATEMENT") { (count, names, values) in
var row = [String: String]()
for index in 0..<Int(count) {
guard let name = names?[index], let value = values?[index] else { continue }
row[String(cString: name)] = String(cString: value)
}
rows.append(row)
}
return rows
}
Update for the given answers to support Swift 5.5.1
let db: OpaquePointer = // the database connection
let sql: String = // the sql string
func callback(context: UnsafeMutableRawPointer?,
columnCount: Int32,
values: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
columns: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?) -> Int32 {
guard let values = values else { return 0 }
guard let columns = columns else { return 0 }
for column in 0 ..< Int(columnCount) {
guard let columnNamePtr = columns[column] else { continue }
guard let valuePtr = values[column] else { continue }
// Note: String(cString:) will copy the values from C to Swift
let column = String(cString: columnNamePtr)
let value = String(cString: valuePtr)
print("\(column) = \(value)")
}
return 0 // status ok
}
var errorMessage = UnsafeMutablePointer<CChar>(nil)
sqlite3_exec(db, sql, callback, nil, &errorMessage)
if let errorMessage = errorMessage {
print(String(cString: errorMessage))
}