顯示具有 寫iOS用得到的記錄 標籤的文章。 顯示所有文章
顯示具有 寫iOS用得到的記錄 標籤的文章。 顯示所有文章

2019年11月13日

Swift String Splite

 

import Foundation

let fullName    = "First Last"
let fullNameArr = fullName.components(separatedBy: " ")

let name    = fullNameArr[0]
let surname = fullNameArr[1]

2019年9月5日

SQLite資料庫,不覆蓋舊資料庫的流程,建議方式 for Swift

完整範例
compareDb.swift

呼叫方式:
compareDbVersion(iDbName: "db",iDbType: "sqlite")



如果想知道原理可以看以下說明:

在製作資料庫的過程,通常可能因為一段時間的使用,使得某些因素,讓我們不得不去建立新的資料表或者是欄位,但覆蓋資料庫不是一個好的作法,以下是說如何在不動到原本的資料情況下,建立新的資料表和欄位。

  以下是寫的流程:

1. 我們將利用比對的方式去查資料庫的資料是否有不一樣。

 if(getLocalDbVersion() != getNewDbVersion())
 {
       
    compareDB()
    //最後修改版本
    update(updateStatementString: "UPDATE dbVersion SET version='\(getNewDbVersion())'")

 }else{
       print("資料庫版本一樣:\(dbVersion)|\(getNewDbVersion())")

 }


2.可以先檢查兩個資料庫版本的不一樣「本機資料庫」、「新的資料庫」。

假設,你的資料庫是叫 db.sqlite

    2.1 在「本機資料庫」開啟的方式,這個只能用iTunes才看得到。

  //開啟本機資料庫
    func openLocalDatabase() -> OpaquePointer? {
        
        var db: OpaquePointer? = nil
        let dirPaths =  NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)
        let docsDir:String! = dirPaths[0]
        let destPath = (docsDir as NSString).appendingPathComponent("/db.sqlite")
        if sqlite3_open(destPath, &db) == SQLITE_OK {
            //print("Successfully opened connection to database at \(destPath)")
            return db
        }
        return nil

    }

    2.2 「新的資料庫」開啟的方式,這個的意思是你放在app裡面的db.sqlite,如圖1:

  //開啟新的sqlite資料
    func openNewDatabase() -> OpaquePointer?{
        var db: OpaquePointer? = nil
        let path = Bundle.main.path(forResource: "db", ofType:"sqlite")
        if sqlite3_open(path, &db) == SQLITE_OK {
            //print("Successfully opened connection to database at \(path)")
            return db
        } else {
            
        }
        return nil

    }

圖1、App的db.sqlite


3.判斷這兩個版本是否一樣,不一樣的話,才進行「第4步」之後的比對動作。以下是取得「本機資料庫」和「新的資料庫」版本方式

      3.1 「本機資料庫」版本的程式

    //取得本機版本
    func getLocalDbVersion()->String{
        
        var Version = ""
        
        var db = openLocalDatabase()
        var queryStatementString = "SELECT version FROM dbVersion"
        var queryStatement: OpaquePointer? = nil
        if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
            if sqlite3_step(queryStatement) == SQLITE_ROW {
                
                let queryResultCol1 = sqlite3_column_text(queryStatement, 0)
                Version = String(cString: queryResultCol1!)
                
            } else {
                print("Query returned no results")
            }
        } else {
            print("SELECT statement could not be prepared")
        }
        
        sqlite3_finalize(queryStatement)
        
        return Version

    }

  3.2 「新的資料庫」版本的程式

    //取得新的資料庫的資料
    func getNewDbVersion()->String
    {
        var Version = ""
        var db = openNewDatabase()
        
        var queryStatementString = "SELECT version FROM dbVersion"
        var queryStatement: OpaquePointer? = nil
        if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
    
            if sqlite3_step(queryStatement) == SQLITE_ROW {
                let queryResultCol1 = sqlite3_column_text(queryStatement, 0)
                Version = String(cString: queryResultCol1!)
            }
            
        } else {
            print("SELECT statement could not be prepared")
        }
        
        sqlite3_finalize(queryStatement)
        return Version
        

    }


4.當版本的比對不一樣時,我們就開始以下的動作。

      4.1 利用 SELECT name, sql FROM sqlite_master WHERE type='table' 取得「新的資料庫」各「資料表的名稱」和「Create Table SQL語法」,圖2。

    4.2 利用迴圈查詢「本機資料庫」的資料表是否和「新的資料表」的資料表相符的資料,語法:SELECT name FROM sqlite_master WHERE type='table' AND name='\(name)'。如果符合,就繼續「檢查欄位」(4.5),如果沒有,就直接利用「Create Table SQL語法」建立新得資料表(4.3、4.4)

圖2

      4.3 比對資料表與欄位的程式碼

  //當資料版本不一樣的時候,會進行,比對db
    func compareDB()
    {
        var dbLocal = openLocalDatabase()//手機本身的sqlite
        var dbNew = openNewDatabase()//新的資料庫
        
        var queryStatementString = "SELECT name, sql FROM sqlite_master WHERE type='table'"
        var queryStatementLocal: OpaquePointer? = nil
        var queryStatementNew: OpaquePointer? = nil
        
        //取得新資料庫的資料表名稱和Crate Table SQL語法
        if sqlite3_prepare_v2(dbNew, queryStatementString, -1, &queryStatementNew, nil) == SQLITE_OK {
            // 
            while sqlite3_step(queryStatementNew) == SQLITE_ROW {
                
                //取得「新資料庫」資料表名稱
                let queryResultCol1 = sqlite3_column_text(queryStatementNew, 0)
                let name = String(cString: queryResultCol1!)
                
                //開始比對「本機資料庫」是否有相對應的資料表
                queryStatementString = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(name)'"
                //
                if sqlite3_prepare_v2(dbLocal, queryStatementString, -1, &queryStatementLocal, nil) == SQLITE_OK {

                    if sqlite3_step(queryStatementLocal) == SQLITE_ROW {
              //如果「本機資料庫」有該比資料,那就再去比對「欄位」
                        compareColumn(tableName: name)
                    }else{
                        //如果「本機資料庫」沒有該資料表,那就取得Create Table SQL語法,建立新的
                        let queryResultCol1 = sqlite3_column_text(queryStatementLocal, 1)
                        let createTableString = String(cString: queryResultCol1!)
                        createTable(createTableString: createTableString)
                    }
                }
                
                
            }
        } else {
            print("SELECT statement could not be prepared")
        }
        
        // 6
        sqlite3_finalize(queryStatementNew)
        sqlite3_finalize(queryStatementLocal)
        

    }

      4.3 建立資料表的Swift寫法如下:

 func createTable(createTableString:String) {
        var db = openLocalDatabase()
        var createTableStatement: OpaquePointer? = nil
        if sqlite3_prepare_v2(db, createTableString, -1, &createTableStatement, nil) == SQLITE_OK {
            if sqlite3_step(createTableStatement) == SQLITE_DONE {
                print("Contact table created.")
            } else {
                print("Contact table could not be created.")
            }
        } else {
            print("CREATE TABLE statement could not be prepared.")
        }
        sqlite3_finalize(createTableStatement)

    }

       4.4 比對欄位的寫法:

  //比較欄位
    func compareColumn(tableName:String)
    {
        var dbNew = openNewDatabase()
        
        var queryStatementString = "pragma table_info(\(tableName))"
        var queryStatementNew: OpaquePointer? = nil
        //取得新的資料表的資料欄位
        if sqlite3_prepare_v2(dbNew, queryStatementString, -1, &queryStatementNew, nil) == SQLITE_OK {
            while sqlite3_step(queryStatementNew) == SQLITE_ROW {
                
                //取得所有欄位名稱
                let queryResultCol1 = sqlite3_column_text(queryStatementNew, 1)
                let fieldName = String(cString: queryResultCol1!)
                
          //判斷本機資料庫欄位是否存在
                if(!isFieldExist(tableName: tableName, fieldName: fieldName))
                {
                     //如果不存在,就在該資料表建立新的欄位
                    let queryResultCol1 = sqlite3_column_text(queryStatementNew, 1)
                    let col1 = String(cString: queryResultCol1!)
                    
                    let queryResultCol2 = sqlite3_column_text(queryStatementNew, 2)
                    let col2 = String(cString: queryResultCol2!)
                    
                    
                    let col3 = sqlite3_column_int(queryStatementNew, 3)
                    let col5 = sqlite3_column_int(queryStatementNew, 5)
                    
                    var sql = "ALTER TABLE \(tableName) ADD COLUMN \(col1) \(col2) ";
                    if col3 == 1 {
                        sql = sql + " not null"
                    }
                    
                    if col5 == 1 {
                        sql = sql + " PRIMARY KEY(\(tableName))";
                    }
                    
                    //建立新的欄位
                    createTable(createTableString: sql)
                    
                }else{
                    print("表格:\(tableName),欄位:\(fieldName) 存在")
                }
                
                
            }
        } else {
            print("SELECT statement could not be prepared")
        }
        
        sqlite3_finalize(queryStatementNew)

    }

       4.5 檢查「本機資料庫」是否有相對應的欄位:

    //檢查本機是否有這個欄位
    func isFieldExist(tableName:String,fieldName:String)->Bool{
        var isExist :Bool = false
        var dbLocal = openLocalDatabase()
        var queryStatementString = "pragma table_info(\(tableName))"
        
        var queryStatementLocal: OpaquePointer? = nil

        if sqlite3_prepare_v2(dbLocal, queryStatementString, -1, &queryStatementLocal, nil) == SQLITE_OK {
            while sqlite3_step(queryStatementLocal) == SQLITE_ROW {
                //檢查「本機資料庫」所有欄位名稱
                let queryResultCol1 = sqlite3_column_text(queryStatementLocal,1)
                let field = String(cString: queryResultCol1!)
               
                if fieldName == field
                {
            //如果一樣的欄位就直接離開。
                    isExist = true
                    break
                }
            }
            
            
        }
        sqlite3_finalize(queryStatementLocal)
        return isExist
        

    }

5.最後、最後,更新本機端的版本號 

檢查完畢後,取得「新的資料庫」版本號,進行「本機資料庫」的更新。
程式碼如下:

   //最後修改版本

    update(updateStatementString: "UPDATE dbVersion SET version='(getNewDbVersion())'")


    func update(updateStatementString:String) {
        var db = openLocalDatabase()
        var updateStatement: OpaquePointer? = nil
        if sqlite3_prepare_v2(db, updateStatementString, -1, &updateStatement, nil) == SQLITE_OK {
            if sqlite3_step(updateStatement) == SQLITE_DONE {
                print("Successfully updated row.")
            } else {
                print("Could not update row.")
            }
        } else {
            print("UPDATE statement could not be prepared")
        }
        sqlite3_finalize(updateStatement)

    }





 

2019年9月4日

2019年9月3日

Swift 如何 Copy 一份.sqlite 到Mobile Device

一、先把建好的 .sqlite 放到自己建立好的資料夾裡,資料夾什麼名稱都沒關係。


二、填入下列程式碼,就可以了。

       
        let dirPaths =  NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)
        let docsDir:String! = dirPaths[0]
        let destPath = (docsDir as NSString).appendingPathComponent("/db.sqlite")//這裡填入你的.sqlite
        let fileMgr = FileManager.default
        if let path = Bundle.main.path(forResource: "db", ofType:"sqlite")
        {
            if !fileMgr.fileExists(atPath: destPath)//如果db不存在,那就直接複製一份
            {
                do {
                    try fileMgr.copyItem(atPath: path, toPath: destPath)
                    print("success")//
                }
                catch let error as NSError
                {
                    print(error.localizedDescription)
                }

            }else{
                print(".sqlite已存在")//

            }
        }

2019年5月3日

Swift 5 讀取 json 檔案及解析

    //CheckList.json
    {
      "CheckList": [
      {
        "CheckItem": "施工計畫書之安全衛生管理計畫",
        "Major": 1,
        "CheckContent": [
        {
            "Major": 1,
            "Minor": 1,
            "CheckItem": "安全衛生管理計畫各項安全檢查"
        },
        {
          "Major": 1,
          "Minor": 2,
          "CheckItem": "工地潛在危險狀況分析及採取相對應之防範措施"
        }
        ]
      }
      ]
    }
    
    //========================================================================================================
    //讀取 Json 資料
    func readJson()
    {
        if let path = Bundle.main.path(forResource: "JsonFile/CheckList", ofType: "json") {
            do {
                
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
                
                if let myJSON = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] {
                    
                    //檢查項目
                    if let data = myJSON["CheckList"] as? [[String: Any]] {
                        for jsonDict in data {
                            var CheckItem = jsonDict["CheckItem"] as? String
                            print("CheckItem:" + CheckItem!)
                            
                            var Major = jsonDict["Major"] as? Int
                            print("Major:" + String(Major!))
                           
                            //檢查內容
                            if let CheckContent = jsonDict["CheckContent"] as? [[String: Any]] {
                                for CheckContentDict in CheckContent {
                                    var CheckItem = CheckContentDict["CheckItem"] as? String
                                    print("CheckItem:" + CheckItem!)

                                    var Major = CheckContentDict["Major"] as? Int
                                    print("Major:" + String(Major!))

                                    var Minor = CheckContentDict["Minor"] as? Int
                                    print("Minor:" + String(Minor!))

                                }
                             }
                        }
                    }
                }
                
            } catch let error {
                print("parse error: \(error.localizedDescription)")
            }
        } else {
            print("Invalid filename/path.")
        }
    }

2018年10月9日

Swift 2D Array add 1D Array(使用 append)



var test2arr:[[Float]] = []
var test1arr:[Float] = [1.0,2.0,3.0]
test2arr.append(test1arr)
test1arr = [4.0,5.0,6.0]
test2arr.append(test1arr)
print(test2arr)



//[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]

Swift 如何回傳 兩個以上的 參數及如何接收。

//回傳方式
func parserE3D(str:String)->([Float],[Int])

{
    var Vertexs:[Float] = []
    var Faces:[Int] = []
    
    .... 一堆程式

    return (Vertexs,Faces)


//接收方式

    var Vertexs:[Float] = []
    var Faces:[Int] = []
    (Vertexs,Faces) = parserE3D(str: datas.hexEncodedString())

2018年10月8日

Swift 16進位(Hex) 轉 Float (依據 IEEE 754)



以 3e4ccccd 轉成 0.2 為範例


    Hex2Float(HexStr: "3e4ccccd")



    //依據 IEEE 754 https://www.h-schmidt.net/FloatConverter/IEEE754.html,16進位轉Float
    func Hex2Float(HexStr:String)
    {
        let binary = Array(get8Hex2Binary(HexStr:HexStr))
        
        let Sign = binary[0...0]
        let Exponent = binary[1...8]
        let Mantissa = binary[9...(binary.count-1)]
        print("Sign:" + Sign)                  //0
        print("Exponent:" + Exponent)          //01111100
        print("Mantissa:" + Mantissa)          //10011001100110011001101
        
        var s = 1.0
        if String(Sign) == "1"
        {
            s = -1.0
        }
        
        let e = Binary2Int(binary: String(Exponent)) - 127
        print("e:" + String(e))                 //-3

        let _2_e = powf(2,Float(e))
        print(_2_e)                             //0.125
        let CalcMant = CalculationMantissa(Mantissa: String(Mantissa))
        let toFloat = Float(s) * _2_e * CalcMant
        print("toFloat:" + String(toFloat))     //0.2
        
    }
    
    //計算Mantissa
    func CalculationMantissa(Mantissa:String) -> Float{
        var calu_m_sum = 0.0
        var e = 0
        for m in Mantissa {
            //println(char)
            e = e - 1
            if m == "1"
            {
                let d = powf(2.0,Float(e))
                calu_m_sum = calu_m_sum + Double(d)
            }
        }
        
        print("calu_m_sum:" + String(1.0 + calu_m_sum))    //1.600000023841858
        return Float(1.0 + calu_m_sum)
    }
    
    //8個位元字串轉成Binary
    func get8Hex2Binary(HexStr:String) -> String{
        var binary = String(Int(HexStr, radix: 16)!, radix: 2)
        print("binary:" +  binary)              //111110010011001100110011001101 未補滿
        if(binary.count != 32)//要補滿32個位元
        {
            for index in binary.count..<32 {
                binary = "0" + binary
            }
        }
        
        print("binary:" +  binary)          //00111110010011001100110011001101 補滿32位元
        return binary
    }
    
    
    //Binary轉Int
    func Binary2Int(binary:String)->Int
    {
        let number = Int(binary, radix: 2)
        return number!
    }

2018年10月5日

Swift String Array 之間轉換及取得字串或陣列中的前5筆資料。



//原始資料
let sample_str = "0123456789"
print(sample_str)         //....0123456789
        
//String 取得前5個字串
let sample_sring_5 =  sample_str[..<sample_str.index(sample_str.startIndex, offsetBy: 5)]
print(sample_sring_5)      //....01234
        
//String 轉 Array
var sample_str_array = Array(sample_str)
print(sample_str_array)     //....["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
        
//Array 取得前5筆陣列值
let sample_array_5 = sample_str_array[0...4]
print(sample_array_5)       //....["0", "1", "2", "3", "4"]
        
//Array 轉 String
let sample_array_2_str = String(sample_array_5)
print(sample_array_2_str)   //....01234

2016年1月18日

Swift Ajax 出現 Error Domain=kCFErrorDomainCFNetwork Code=-1022 問題。

找到 info.plist 加入

 <key>NSAppTransportSecurity</key>
 <dict>
 <key>NSAllowsArbitraryLoads</key>
 <true/>
 </dict>