स्विफ्ट में SQLite डेटाबेस एक्सेस करना


103

मैं स्विफ्ट कोड के साथ अपने ऐप में एक SQLite डेटाबेस तक पहुंचने का रास्ता ढूंढ रहा हूं।

मुझे पता है कि मैं ऑब्जेक्टिव C में एक SQLite Wrapper का उपयोग कर सकता हूं और ब्रिजिंग हेडर का उपयोग कर सकता हूं, लेकिन मैं इस प्रोजेक्ट को पूरी तरह से स्विफ्ट में कर पाऊंगा। क्या ऐसा करने का एक तरीका है, यदि ऐसा है, तो क्या कोई मुझे एक संदर्भ के लिए इंगित कर सकता है जो दिखाता है कि कैसे एक क्वेरी सबमिट करें, पंक्तियों को पुनः प्राप्त करें, आदि?



1
मुझे अपना डेटाबेस फ़ाइल कहां रखना चाहिए?
सी। फेलियाना

1
@ C.Feliana - अनुप्रयोग समर्थन निर्देशिका एक महान जगह है, उदाहरण के लिए let dbPath = try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("test.sqlite").path
रॉब

जवाबों:


143

जब आपको शायद कई SQLite रैपर में से एक का उपयोग करना चाहिए, अगर आप जानना चाहते थे कि खुद को SQLite लाइब्रेरी कैसे कहें, तो आप निम्न कार्य करेंगे:

  1. SQLite C कॉल्स को हैंडल करने के लिए अपने स्विफ्ट प्रोजेक्ट को कॉन्फ़िगर करें। यदि Xcode 9 या उसके बाद का उपयोग कर रहे हैं, तो आप बस कर सकते हैं:

    import SQLite3
  2. डेटाबेस बनाएँ / खोलें।

    let fileURL = try! FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("test.sqlite")
    
    // open database
    
    var db: OpaquePointer?
    guard sqlite3_open(fileURL.path, &db) == SQLITE_OK else {
        print("error opening database")
        sqlite3_close(db)
        db = nil
        return
    }
    

    ध्यान दें, मुझे पता है कि इसे खोलने में विफलता पर डेटाबेस को बंद करना अजीब लगता है, लेकिन sqlite3_open प्रलेखन स्पष्ट करता है कि हमें ऐसा करने से बचना चाहिए:

    इसे खोले जाने पर कोई त्रुटि होती है या नहीं, डेटाबेस कनेक्शन हैंडल से जुड़े संसाधनों को इसे तब जारी करके जारी किया जाना चाहिए, sqlite3_close()जब इसकी आवश्यकता नहीं है।

  3. sqlite3_execSQL प्रदर्शन करने के लिए उपयोग करें (जैसे तालिका बनाएँ)।

    if sqlite3_exec(db, "create table if not exists test (id integer primary key autoincrement, name text)", nil, nil, nil) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error creating table: \(errmsg)")
    }
    
  4. sqlite3_prepare_v2SQL को ?प्लेसहोल्डर के साथ तैयार करने के लिए उपयोग करें जिसके लिए हम मान को बांधेंगे।

    var statement: OpaquePointer?
    
    if sqlite3_prepare_v2(db, "insert into test (name) values (?)", -1, &statement, nil) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error preparing insert: \(errmsg)")
    }
    
    if sqlite3_bind_text(statement, 1, "foo", -1, SQLITE_TRANSIENT) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("failure binding foo: \(errmsg)")
    }
    
    if sqlite3_step(statement) != SQLITE_DONE {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("failure inserting foo: \(errmsg)")
    }
    

    ध्यान दें, वह SQLITE_TRANSIENTस्थिरांक का उपयोग करता है जिसे निम्नानुसार लागू किया जा सकता है:

    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
    
  5. किसी अन्य मान सम्मिलित करने के लिए SQL रीसेट करें। इस उदाहरण में, मैं एक NULLमान डालूँगा:

    if sqlite3_reset(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error resetting prepared statement: \(errmsg)")
    }
    
    if sqlite3_bind_null(statement, 1) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("failure binding null: \(errmsg)")
    }
    
    if sqlite3_step(statement) != SQLITE_DONE {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("failure inserting null: \(errmsg)")
    }
    
  6. उस तैयार किए गए स्टेटमेंट से जुड़ी मेमोरी को रिकवर करने के लिए तैयार स्टेटमेंट को अंतिम रूप दें:

    if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }
    
    statement = nil
    
  7. मूल्यों को प्राप्त करने के माध्यम से तालिका और लूप से मूल्यों का चयन करने के लिए नया विवरण तैयार करें:

    if sqlite3_prepare_v2(db, "select id, name from test", -1, &statement, nil) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error preparing select: \(errmsg)")
    }
    
    while sqlite3_step(statement) == SQLITE_ROW {
        let id = sqlite3_column_int64(statement, 0)
        print("id = \(id); ", terminator: "")
    
        if let cString = sqlite3_column_text(statement, 1) {
            let name = String(cString: cString)
            print("name = \(name)")
        } else {
            print("name not found")
        }
    }
    
    if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }
    
    statement = nil
    
  8. डेटाबेस बंद करें:

    if sqlite3_close(db) != SQLITE_OK {
        print("error closing database")
    }
    
    db = nil

स्विफ्ट 2 और Xcode के पुराने संस्करणों के लिए, इस उत्तर के पिछले संशोधन देखें ।


1
जिन लोगों को पास 1 पर कुछ समस्याएँ मिलीं, उनके लिए इस पर विचार करें: अपने Xcode प्रोजेक्ट में एक ब्रिजिंग हेडर बनाएँ (जैसे BridgingHeader.h); इस हेडर फ़ाइल में केवल स्विफ्ट (उदाहरण के लिए #include <sqlite3.h>) के लिए उद्देश्य-सी / सी हेडर आयात करने वाली लाइनें हो सकती हैं; "बिल्ड सेटिंग्स" पर "ऑब्जेक्टिव-सी ब्रिजिंग हैडर" खोजें (आप सर्च बार का उपयोग कर सकते हैं) और "ब्रिजिंगहेडर.एच" टाइप करें (यदि आपको कोई त्रुटि संदेश मिलता है जैसे "ऑब्जेक्टिव-सी हेडर आयात नहीं कर सका", तो "प्रोजेक्ट- ट्राई करें" नाम / BridgingHeader.h "); "बिल्ड चरणों", "लिंक बाइनरी विद लाइब्रेरीज़" पर जाएं, और libsqlite3.0.dylib या libsqlite3.0.tbd को XCode 7 में जोड़ें
Jorg B Jorge

क्या बेहतर होगा कि अगर (... == SQLITE_OK) घोंसला बनाया जाए ताकि निम्नलिखित विफल न हो जाए। मैं विशुद्ध रूप से पूछ रहा हूं क्योंकि मैं इसके लिए बहुत नया हूं और यदि आप शिक्षण उद्देश्यों के लिए ऐसा करते हैं तो मैं बहुत उत्सुक था।
चतुर्थी

@quemeful - ज़रूर, लेकिन अगर आप ऐसा कई SQLite कॉल के साथ करते हैं, तो आप कोड के साथ समाप्त हो जाते हैं जो वास्तव में गहरा घोंसला है। यदि आप इस बारे में चिंतित हैं, तो मैं शायद guardइसके बजाय बयानों का उपयोग करूंगा ।
रोब

@ जोर्ज बी जॉर्ज मैंने सब कुछ किया है, क्या आपको भी किसी तरह से हेडर आयात करने की आवश्यकता है? मैं टेस्ट क्लास में काम कर रहा हूँ
Async-

हाय @ रोब, मैं यहाँ एक स्विफ्ट परियोजना में आपके साइक्लाइट रैपर का उपयोग कर रहा हूँ। यह वास्तव में अच्छा है, धन्यवाद। हालाँकि, मैं इसके साथ तालिका से एक चुनिंदा गिनती (*) नहीं कर सकता। यह दुर्घटनाग्रस्त रहता है। अगर मैंने tablename जहाँ कुछ_col = xxx से सेलेक्ट काउंट (col_name) किया, तो यह काम करता है। आपकी क्या सलाह है?
gebroscience

18

आप जो सबसे अच्छा काम कर सकते हैं वह डायनेमिक लाइब्रेरी को ब्रिजिंग हेडर के अंदर आयात करना है:

  1. Libsqlite3.dylib को अपने "लिंक बाइनरी विद लाइब्रेरीज़" बिल्ड चरण में जोड़ें
  2. एक "ब्रिजिंग-हैडर.एच" बनाएं और #import <sqlite3.h>शीर्ष पर जोड़ें
  3. "स्विफ्ट कंपाइलर - कोड जेनरेशन" के तहत बिल्ड सेटिंग्स में "ऑब्जेक्टिव-सी ब्रिजिंग हैडर" सेटिंग के लिए "ब्रिजिंग-हेडर। एच।"

फिर आप sqlite3_openअपने स्विफ्ट कोड से सभी सी तरीकों को एक्सेस कर पाएंगे ।

हालाँकि, आप बस एफएमडीबी का उपयोग करना चाहते हैं और आयात कर सकते हैं कि ब्रिजिंग हेडर के माध्यम से जैसे कि साइक्लाइट का एक अधिक वस्तु उन्मुख आवरण है। सी पॉइंटर्स और स्ट्रक्चर्स से निपटना स्विफ्ट में बोझिल होगा।


मुझे प्रोजेक्ट बिल्ड सेटिंग्स के तहत इसे जोड़ना था और ब्रिजिंग हेडर खोजने के लिए Xcode के लिए टारगेट बिल्ड सेटिंग्स नहीं।
रोब 5408

3
सभी ने और उनके पिता ने अब एक स्विफ्ट रैपर बनाया है। नीचे देखें
quemeful

1
अफसोस की बात है, उनमें से कोई भी बहुत परिपक्व नहीं है, इसलिए यदि आप इनमें से किसी भी नए आवरण का उपयोग करते हैं, तो सावधान रहें। उदाहरण के लिए, लेखन के समय, मैंने उनमें से चार को देखा, और तीन को गलत तरीके से संभाला और चौथे ने उन्हें बिल्कुल नहीं संभाला।
रोब

@Rob क्या आपने github.com/stephencelis/SQLite.swift#readme को देखा है ? NSDate के साथ उपयोग करने के लिए यहाँ कॉन्फ़िगर करने की जानकारी: github.com/stephencelis/SQLite.swift/blob/master/Documentation/…
stephencelis

@stephencelis अरे, यह उनमें से ज्यादातर से बेहतर है, क्योंकि कम से कम आप टाइमज़ोन निर्दिष्ट करते हैं, लेकिन मेरे पास अभी भी इसके साथ मुद्दे हैंNSDateFormatter । लेकिन मेरा इरादा इन विशेष कार्यान्वयनों के इस विशेष पहलू की आलोचना करने से कम था, यह सुझाव देने की तुलना में कि यह व्यापक मुद्दे का संकेत है, कि इन वर्षों में शोधन नहीं किया गया है जो कि एफएमडीबी जैसे समाधान हैं। मुझे लगता है कि लोग कम परिपक्व स्विफ्ट कार्यान्वयन (TFHpple बनाम NDHpple एक और अच्छा उदाहरण हैं) के पक्ष में सिद्ध उद्देश्य-सी समाधान को छोड़ने के लिए बहुत जल्दी हैं।
रोब

11

मैं भी SQLite के साथ बातचीत करने के लिए किसी तरह की तलाश कर रहा था, जिस तरह से मुझे ऑब्जेक्टिव-सी में पहले करने की आदत थी। बेशक, C संगतता के कारण, मैंने सीधे C API का उपयोग किया।

जैसा कि स्विफ्ट में SQLite के लिए कोई आवरण मौजूद नहीं है और ऊपर उल्लिखित SQLiteDB कोड कुछ उच्च स्तर पर है और कुछ उपयोग को मानता है, मैंने एक आवरण बनाने और प्रक्रिया में स्विफ्ट से थोड़ा परिचित होने का निर्णय लिया। आप इसे यहां पा सकते हैं: https://github.com/chrismsimpson/SwiftSQLite

var db = SQLiteDatabase();
db.open("/path/to/database.sqlite");

var statement = SQLiteStatement(database: db);

if ( statement.prepare("SELECT * FROM tableName WHERE Id = ?") != .Ok )
{
    /* handle error */
}

statement.bindInt(1, value: 123);

if ( statement.step() == .Row )
{
    /* do something with statement */
    var id:Int = statement.getIntAt(0)
    var stringValue:String? = statement.getStringAt(1)
    var boolValue:Bool = statement.getBoolAt(2)
    var dateValue:NSDate? = statement.getDateAt(3)
}

statement.finalizeStatement(); /* not called finalize() due to destructor/language keyword */

5

मैंने पूरी तरह से स्विफ्टडाईट नामक स्विफ्ट SQLite लाइब्रेरी बनाई है जिसे स्विफ्टडाटा कहा जाता है ।

इसकी कुछ विशेषताएं हैं:

  • वस्तुओं को आसानी से एसक्यूएल के स्ट्रिंग से बांधें
  • लेनदेन और बचत के लिए समर्थन
  • इनलाइन त्रुटि से निपटने
  • डिफ़ॉल्ट रूप से पूरी तरह से सुरक्षित थ्रेड

यह 'परिवर्तनों' को निष्पादित करने का एक आसान तरीका प्रदान करता है (जैसे INSERT, UPDATE, DELETE, आदि):

if let err = SD.executeChange("INSERT INTO Cities (Name, Population, IsWarm, FoundedIn) VALUES ('Toronto', 2615060, 0, '1793-08-27')") {
    //there was an error during the insert, handle it here
} else {
    //no error, the row was inserted successfully
}

और 'प्रश्न' (उदाहरण के लिए):

let (resultSet, err) = SD.executeQuery("SELECT * FROM Cities")
if err != nil {
    //there was an error during the query, handle it here
} else {
    for row in resultSet {
        if let name = row["Name"].asString() {
            println("The City name is: \(name)")
        }
        if let population = row["Population"].asInt() {
            println("The population is: \(population)")
        }
        if let isWarm = row["IsWarm"].asBool() {
            if isWarm {
                println("The city is warm")
            } else {
                println("The city is cold")
            }
        }
        if let foundedIn = row["FoundedIn"].asDate() {
            println("The city was founded in: \(foundedIn)")
        }
    }
}

साथ में और भी कई सुविधाएँ!

आप इसे यहां देख सकते हैं


दुर्भाग्य से आपका दायित्व केवल आईओएस है! : - /
बैडमिंटनकैट

3

अभी तक स्विफ्ट 2 और स्विफ्ट 3 के लिए एक और SQLite आवरण: http://github.com/groue/GRDB.swift

विशेषताएं:

  • एक एपीआई जो ccgus / fmdb के उपयोगकर्ताओं को परिचित लगेगा

  • एक निम्न-स्तरीय SQLite API जो स्विफ्ट मानक लाइब्रेरी का लाभ उठाता है

  • SQL- एलर्जी डेवलपर्स के लिए एक सुंदर स्विफ्ट क्वेरी इंटरफ़ेस

  • SQLite वाल मोड के लिए समर्थन, और अतिरिक्त प्रदर्शन के लिए समवर्ती डेटाबेस का उपयोग

  • एक रिकॉर्ड क्लास जो परिणाम सेट को लपेटता है, नाश्ते के लिए आपके कस्टम एसक्यूएल प्रश्नों को खाता है, और बुनियादी सीआरयूडी संचालन प्रदान करता है

  • स्विफ्ट प्रकार की स्वतंत्रता: सही स्विफ्ट प्रकार चुनें जो आपके डेटा को फिट करता है। जरूरत पड़ने पर Int64 का उपयोग करें, या सुविधाजनक Int के साथ रहें। NSDate या NSDateCompords को स्टोर करें और पढ़ें। असतत डेटा प्रकारों के लिए स्विफ्ट एनमों की घोषणा करें। अपने स्वयं के डेटाबेस-परिवर्तनीय प्रकारों को परिभाषित करें।

  • डेटाबेस माइग्रेशन

  • गति: https://github.com/groue/GRDB.swift/wiki/Performance


जीआरडीबी जीथब पर सबसे अच्छी तरह से प्रलेखित, समर्थित और अनुरक्षित ढांचों में से एक है!
कलस

3

AppDelegate.swift

func createDatabase()
{
    var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
    let directory:String=path[0]
    let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite")

    print(DBpath)

    if (FileManager.default.fileExists(atPath: DBpath))
    {
        print("Successfull database create")
    }
    else
    {
        let pathfrom:String=(Bundle.main.resourcePath! as NSString).appendingPathComponent("Food.sqlite")

        var success:Bool
        do {
            try FileManager.default.copyItem(atPath: pathfrom, toPath: DBpath)
            success = true
        } catch _ {
            success = false
        }

        if !success
        {
            print("database not create ")
        }
        else
        {
            print("Successfull database new create")
        }
    }
}

Database.swift

import UIKit

class database: NSObject
{
func databasePath() -> NSString
{
    var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
    let directory:String=path[0] 
    let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite")

    if (FileManager.default.fileExists(atPath: DBpath))
    {
        return DBpath as NSString
    }
    return DBpath as NSString
}

func ExecuteQuery(_ str:String) -> Bool
{
    var result:Bool=false
    let DBpath:String=self.databasePath() as String

    var db: OpaquePointer? = nil
    var stmt:OpaquePointer? = nil

    let strExec=str.cString(using: String.Encoding.utf8)

    if (sqlite3_open(DBpath, &db)==SQLITE_OK)
    {
        if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
        {
            if (sqlite3_step(stmt) == SQLITE_DONE)
            {
                result=true
            } 
        }
        sqlite3_finalize(stmt)
    }
    sqlite3_close(db)

    return result
}

func SelectQuery(_ str:String) -> Array<Dictionary<String,String>>
{
    var result:Array<Dictionary<String,String>>=[]
    let DBpath:String=self.databasePath() as String

    var db: OpaquePointer? = nil
    var stmt:OpaquePointer? = nil

    let strExec=str.cString(using: String.Encoding.utf8)

    if ( sqlite3_open(DBpath,&db) == SQLITE_OK)
    {
        if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
        {
            while (sqlite3_step(stmt) == SQLITE_ROW)
            {
                var i:Int32=0
                let icount:Int32=sqlite3_column_count(stmt)

                var dict=Dictionary<String, String>()

                while i < icount
                {
                    let strF=sqlite3_column_name(stmt, i)
                    let strV = sqlite3_column_text(stmt, i)

                    let rFiled:String=String(cString: strF!)
                    let rValue:String=String(cString: strV!)
                    //let rValue=String(cString: UnsafePointer<Int8>(strV!))

                    dict[rFiled] = rValue

                    i += 1
                }
                result.insert(dict, at: result.count)
            }
        sqlite3_finalize(stmt)
        }

    sqlite3_close(db)
    }
    return result
}

func AllSelectQuery(_ str:String) -> Array<Model>
{
    var result:Array<Model>=[]
    let DBpath:String=self.databasePath() as String

    var db: OpaquePointer? = nil
    var stmt:OpaquePointer? = nil

    let strExec=str.cString(using: String.Encoding.utf8)

    if ( sqlite3_open(DBpath,&db) == SQLITE_OK)
    {
        if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
        {
            while (sqlite3_step(stmt) == SQLITE_ROW)
            {
                let mod=Model()

                mod.id=String(cString: sqlite3_column_text(stmt, 0))
                mod.image=String(cString: sqlite3_column_text(stmt, 1))
                mod.name=String(cString: sqlite3_column_text(stmt, 2))
                mod.foodtype=String(cString: sqlite3_column_text(stmt, 3))
                mod.vegtype=String(cString: sqlite3_column_text(stmt, 4))
                mod.details=String(cString: sqlite3_column_text(stmt, 5))

                result.insert(mod, at: result.count)
            }
            sqlite3_finalize(stmt)
        }
        sqlite3_close(db)
    }
    return result
}

}

Model.swift

import UIKit


class Model: NSObject
{
var uid:Int = 0
var id:String = ""
var image:String = ""
var name:String = ""
var foodtype:String = ""
var vegtype:String = ""
var details:String = ""
var mealtype:String = ""
var date:String = ""
}

एक्सेस डेटाबेस:

let DB=database()
var mod=Model()

डेटाबेस क्वेरी आग:

var DailyResult:Array<Model> = DB.AllSelectQuery("select * from food where foodtype == 'Sea Food' ORDER BY name ASC")

यह क्यूरी काम नहीं कर रहा है। सिर्फ एक = के बजाय == क्यों है?
ArgaPK

1

यह अब तक की सर्वश्रेष्ठ SQLite लाइब्रेरी है जिसका मैंने स्विफ्ट में उपयोग किया है: https://github.com/stephencelis/SQL/.

कोड के उदाहरण देखें। सी एपीआई की तुलना में बहुत अधिक क्लीनर:

import SQLite

let db = try Connection("path/to/db.sqlite3")

let users = Table("users")
let id = Expression<Int64>("id")
let name = Expression<String?>("name")
let email = Expression<String>("email")

try db.run(users.create { t in
    t.column(id, primaryKey: true)
    t.column(name)
    t.column(email, unique: true)
})
// CREATE TABLE "users" (
//     "id" INTEGER PRIMARY KEY NOT NULL,
//     "name" TEXT,
//     "email" TEXT NOT NULL UNIQUE
// )

let insert = users.insert(name <- "Alice", email <- "alice@mac.com")
let rowid = try db.run(insert)
// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com')

for user in try db.prepare(users) {
    print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
    // id: 1, name: Optional("Alice"), email: alice@mac.com
}
// SELECT * FROM "users"

let alice = users.filter(id == rowid)

try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
// WHERE ("id" = 1)

try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)

try db.scalar(users.count) // 0
// SELECT count(*) FROM "users"

प्रलेखन यह भी कहता है कि "SQLite.swift C API पर एक हल्के, स्विफ्ट-फ्रेंडली आवरण के रूप में भी काम करता है," और इसके कुछ उदाहरणों का अनुसरण करता है।


0

मैंने स्विफ्ट में SQLite3 रैपर लाइब्रेरी लिखी है

यह वास्तव में बहुत ही साधारण एपीआई के साथ एक बहुत ही उच्च स्तर का आवरण है, लेकिन वैसे भी, इसमें निम्न-स्तरीय सी अंतर-ऑप कोड है, और मैं यहां सी (-सुधार) को सी-ऑप दिखाता है।

    struct C
    {
        static let  NULL        =   COpaquePointer.null()
    }

    func open(filename:String, flags:OpenFlag)
    {
        let name2   =   filename.cStringUsingEncoding(NSUTF8StringEncoding)!
        let r       =   sqlite3_open_v2(name2, &_rawptr, flags.value, UnsafePointer<Int8>.null())
        checkNoErrorWith(resultCode: r)
    }

    func close()
    {   
        let r   =   sqlite3_close(_rawptr)
        checkNoErrorWith(resultCode: r)
        _rawptr =   C.NULL
    }

    func prepare(SQL:String) -> (statements:[Core.Statement], tail:String)
    {
        func once(zSql:UnsafePointer<Int8>, len:Int32, inout zTail:UnsafePointer<Int8>) -> Core.Statement?
        {
            var pStmt   =   C.NULL
            let r       =   sqlite3_prepare_v2(_rawptr, zSql, len, &pStmt, &zTail)
            checkNoErrorWith(resultCode: r)

            if pStmt == C.NULL
            {
                return  nil
            }
            return  Core.Statement(database: self, pointerToRawCStatementObject: pStmt)
        }

        var stmts:[Core.Statement]  =   []
        let sql2    =   SQL as NSString
        var zSql    =   UnsafePointer<Int8>(sql2.UTF8String)
        var zTail   =   UnsafePointer<Int8>.null()
        var len1    =   sql2.lengthOfBytesUsingEncoding(NSUTF8StringEncoding);
        var maxlen2 =   Int32(len1)+1

        while let one = once(zSql, maxlen2, &zTail)
        {
            stmts.append(one)
            zSql    =   zTail
        }

        let rest1   =   String.fromCString(zTail)
        let rest2   =   rest1 == nil ? "" : rest1!

        return  (stmts, rest2)
    }

    func step() -> Bool
    {   
        let rc1 =   sqlite3_step(_rawptr)

        switch rc1
        {   
            case SQLITE_ROW:
                return  true

            case SQLITE_DONE:
                return  false

            default:
                database.checkNoErrorWith(resultCode: rc1)
        }
    }

    func columnText(at index:Int32) -> String
    {
        let bc  =   sqlite3_column_bytes(_rawptr, Int32(index))
        let cs  =   sqlite3_column_text(_rawptr, Int32(index))

        let s1  =   bc == 0 ? "" : String.fromCString(UnsafePointer<CChar>(cs))!
        return  s1
    }

    func finalize()
    {
        let r   =   sqlite3_finalize(_rawptr)
        database.checkNoErrorWith(resultCode: r)

        _rawptr =   C.NULL
    }

यदि आप इस निम्न स्तर के आवरण का पूर्ण स्रोत कोड चाहते हैं, तो इन फ़ाइलों को देखें।


0

SQLite C कॉल को संभालने के लिए अपने स्विफ्ट प्रोजेक्ट को कॉन्फ़िगर करें:

प्रोजेक्ट के लिए ब्रिजिंग हेडर फ़ाइल बनाएँ। कोको और उद्देश्य-सी के साथ प्रयोग स्विफ्ट के स्विफ्ट अनुभाग में आयात उद्देश्य-सी देखें। इस ब्रिजिंग हेडर को sqlite3.h आयात करना चाहिए:

अपनी परियोजना में libsqlite3.0.dylib जोड़ें। किसी प्रोजेक्ट में लाइब्रेरी / फ्रेमवर्क जोड़ने के बारे में Apple के दस्तावेज़ देखें।

और निम्नलिखित कोड का उपयोग किया

    func executeQuery(query: NSString ) -> Int
    {
        if  sqlite3_open(databasePath! as String, &database) != SQLITE_OK
        {
            println("Databse is not open")
            return 0
        }
        else
        {
            query.stringByReplacingOccurrencesOfString("null", withString: "")
            var cStatement:COpaquePointer = nil
            var executeSql = query as NSString
            var lastId : Int?
            var sqlStatement = executeSql.cStringUsingEncoding(NSUTF8StringEncoding)
            sqlite3_prepare_v2(database, sqlStatement, -1, &cStatement, nil)
            var execute = sqlite3_step(cStatement)
            println("\(execute)")
            if execute == SQLITE_DONE
            {
                lastId = Int(sqlite3_last_insert_rowid(database))
            }
            else
            {
                println("Error in Run Statement :- \(sqlite3_errmsg16(database))")
            }
            sqlite3_finalize(cStatement)
            return lastId!
        }
    }
    func ViewAllData(query: NSString, error: NSError) -> NSArray
    {
        var cStatement = COpaquePointer()
        var result : AnyObject = NSNull()
        var thisArray : NSMutableArray = NSMutableArray(capacity: 4)
        cStatement = prepare(query)
        if cStatement != nil
        {
            while sqlite3_step(cStatement) == SQLITE_ROW
            {
                result = NSNull()
                var thisDict : NSMutableDictionary = NSMutableDictionary(capacity: 4)
                for var i = 0 ; i < Int(sqlite3_column_count(cStatement)) ; i++
                {
                    if sqlite3_column_type(cStatement, Int32(i)) == 0
                    {
                        continue
                    }
                    if sqlite3_column_decltype(cStatement, Int32(i)) != nil && strcasecmp(sqlite3_column_decltype(cStatement, Int32(i)), "Boolean") == 0
                    {
                        var temp = sqlite3_column_int(cStatement, Int32(i))
                        if temp == 0
                        {
                            result = NSNumber(bool : false)
                        }
                        else
                        {
                            result = NSNumber(bool : true)
                        }
                    }
                    else if sqlite3_column_type(cStatement,Int32(i)) == SQLITE_INTEGER
                    {
                        var temp = sqlite3_column_int(cStatement,Int32(i))
                        result = NSNumber(int : temp)
                    }
                    else if sqlite3_column_type(cStatement,Int32(i)) == SQLITE_FLOAT
                    {
                        var temp = sqlite3_column_double(cStatement,Int32(i))
                        result = NSNumber(double: temp)
                    }
                    else
                    {
                        if sqlite3_column_text(cStatement, Int32(i)) != nil
                        {
                            var temp = sqlite3_column_text(cStatement,Int32(i))
                            result = String.fromCString(UnsafePointer<CChar>(temp))!
                            
                            var keyString = sqlite3_column_name(cStatement,Int32(i))
                            thisDict.setObject(result, forKey: String.fromCString(UnsafePointer<CChar>(keyString))!)
                        }
                        result = NSNull()

                    }
                    if result as! NSObject != NSNull()
                    {
                        var keyString = sqlite3_column_name(cStatement,Int32(i))
                        thisDict.setObject(result, forKey: String.fromCString(UnsafePointer<CChar>(keyString))!)
                    }
                }
                thisArray.addObject(NSMutableDictionary(dictionary: thisDict))
            }
            sqlite3_finalize(cStatement)
        }
        return thisArray
    }
    func prepare(sql : NSString) -> COpaquePointer
    {
        var cStatement:COpaquePointer = nil
        sqlite3_open(databasePath! as String, &database)
        var utfSql = sql.UTF8String
        if sqlite3_prepare(database, utfSql, -1, &cStatement, nil) == 0
        {
            sqlite3_close(database)
            return cStatement
        }
        else
        {
            sqlite3_close(database)
            return nil
        }
    }
}

0

कभी-कभी, sqlite.org पर दिखाए गए "SQLite in 5 मिनट या उससे कम" का एक स्विफ्ट संस्करण पर्याप्त है। "5 मिनट या उससे कम" दृष्टिकोण का उपयोग करता है , जिसके लिए एक सुविधा आवरण है , , , और ।sqlite3_exec()sqlite3_prepare()sqlite3_step()sqlite3_column()sqlite3_finalize()

स्विफ्ट 2.2 सीधे तौर पर sqlite3_exec() callbackफ़ंक्शन पॉइंटर का समर्थन कर सकता है क्योंकि यह एक वैश्विक, गैर-इंस्टेंस प्रक्रिया funcया गैर-कैप्चरिंग शाब्दिक बंद है {}

पठनीय typealias

typealias sqlite3 = COpaquePointer
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
typealias CCharPointer = UnsafeMutablePointer<CChar>
typealias CVoidPointer = UnsafeMutablePointer<Void>

कॉलबैक दृष्टिकोण

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
}

बंद करने का दृष्टिकोण

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
}

SQLite के रूप में C लाइब्रेरी को कॉल करने के लिए एक Xcode प्रोजेक्ट तैयार करने के लिए, (1) एक Bridging-Header.h फ़ाइल संदर्भ C हेडर को #import "sqlite3.h"जोड़ने की आवश्यकता है , (2) जैसे Bridging-Header.h को Objective-C Bridging Header को प्रोजेक्ट में जोड़ें। सेटिंग्स, और (3) जोड़ने libsqlite3.tbdके लिए लाइब्रेरी के साथ लिंक बाइनरी लक्ष्य सेटिंग की।

Sqlite.org की "5 मिनट या उससे कम में SQLite" उदाहरण के एक स्विफ्ट Xcode7 परियोजना में कार्यान्वित किया जाता है यहाँ


0

आप इस लाइब्रेरी का उपयोग स्विफ्ट में SQLite https://github.com/pmurphyjam/SQLiteDemo के लिए कर सकते हैं

SQLiteDemo

SQLite डेमो का उपयोग स्विफ्ट SQLDataAccess वर्ग स्विफ्ट में लिखा है

अपने प्रोजेक्ट में जोड़ना

आपको अपने प्रोजेक्ट में जोड़ने के लिए केवल तीन फाइलों की आवश्यकता है * SQLDataAccess.swift * DataConstants.swift * ब्रिजिंग-हेडर। ब्रिजिंग-हेडर को आपके स्विफ्ट कंपाइलर - जनरल 'के तहत आपके Xcode के प्रोजेक्ट' ऑब्जेक्टिव-सी ब्रिजिंग हेडर 'में सेट किया जाना चाहिए।

उपयोग के लिए उदाहरण

SQLDataAccess.swift के साथ सरल एसक्यूएल लिखने के तरीके को देखने के लिए बस ViewController.swift में कोड का पालन करें। सबसे पहले आपको अपने साथ काम करने वाले SQLite डेटाबेस को खोलने की आवश्यकता है

    let db = SQLDataAccess.shared
    db.setDBName(name:"SQLite.db")
    let opened = db.openConnection(copyFile:true)

यदि ओपनकॉइन सफल हुआ, तो अब आप टेबल ऐपइन्फो में एक साधारण इंसर्ट कर सकते हैं

    //Insert into Table AppInfo
    let status = db.executeStatement("insert into AppInfo (name,value,descrip,date) values(?,?,?,?)",SQLiteDemo","1.0.2","unencrypted",Date())
    if(status)
    {
        //Read Table AppInfo into an Array of Dictionaries
        let results = db.getRecordsForQuery("select * from AppInfo ")
        NSLog("Results = \(results)")
    }

देखो कितना सरल था!

Db.executeStatement में पहला पद स्ट्रिंग के रूप में आपकी एसक्यूएल है, जो सभी शर्तों का पालन करती हैं वे किसी भी प्रकार की एक वैरिएड तर्क सूची हैं, और एक ऐरे में आपके पैरामीटर हैं। ये सभी शर्तें SQL तर्कों की आपकी सूची में अल्पविराम से अलग हो जाती हैं। आप सीक्वल स्टेटमेंट के ठीक बाद स्ट्रिंग्स, इंटेगर, डेट और ब्लब्स में प्रवेश कर सकते हैं क्योंकि इन सभी को सीक्वल के लिए पैरामीटर माना जाता है। वैरिएड तर्क सरणी सिर्फ एक निष्पादित या getRecordsForQuery कॉल में अपने सभी अगली कड़ी में प्रवेश करने के लिए सुविधाजनक बनाता है। यदि आपके पास कोई पैरामीटर नहीं है, तो अपने SQL के बाद कुछ भी दर्ज न करें।

परिणाम सरणी एक सरणी का शब्दकोश है जहाँ 'कुंजी' आपके टेबल कॉलम का नाम है, और 'वैल्यू' आपका डेटा SQLite द्वारा प्राप्त किया गया है। आप आसानी से लूप के लिए इस सरणी के माध्यम से पुनरावृत्ति कर सकते हैं या इसे सीधे प्रिंट कर सकते हैं या इन डेटा तत्वों को कस्टम डेटा ऑब्जेक्ट क्लासेस को असाइन कर सकते हैं जो आप मॉडल खपत के लिए अपने व्यू कंट्रोलर्स में उपयोग करते हैं।

    for dic in results as! [[String:AnyObject]] {
       print(“result = \(dic))
    }

SQLDataAccess स्टोर करेगा, पाठ, डबल, फ्लोट, बूँद, दिनांक, पूर्णांक और लंबे लंबे पूर्णांक। ब्लब्स के लिए आप बाइनरी, वार्बिनरी, ब्लॉब स्टोर कर सकते हैं।

Text के लिए आप char, character, clob, national varying character, native character, nchar, nvarchar, varchar, variant, varying character, text स्टोर कर सकते हैं।

डेट्स के लिए आप डेटाइम, टाइम, टाइमस्टैम्प, डेट स्टोर कर सकते हैं।

Integers के लिए आप bigint, bit, bool, boolean, int2, int8, integer, mediumint, smallint, smallint, int स्टोर कर सकते हैं।

डबल्स के लिए आप दशमलव, डबल परिशुद्धता, फ्लोट, न्यूमेरिक, रियल, डबल स्टोर कर सकते हैं। डबल में सबसे अधिक सटीकता है।

तुम भी नल के नल की दुकान कर सकते हैं।

ViewController.swift में एक और जटिल उदाहरण दिखाया गया है कि कैसे एक शब्दकोश को 'बूँद' के रूप में सम्मिलित किया जाए। इसके अलावा SQLDataAccess देशी स्विफ्ट दिनांक () को समझता है ताकि आप इन वस्तुओं को परिवर्तित करने के साथ सम्मिलित कर सकें, और यह उन्हें पाठ में परिवर्तित करेगा और उन्हें संग्रहीत करेगा, और जब पुनर्प्राप्त किया जाएगा तो उन्हें पाठ से दिनांक में परिवर्तित कर सकते हैं।

बेशक SQLite की असली शक्ति यह लेनदेन क्षमता है। यहाँ आप वस्तुतः 400 SQL कथनों को मापदंडों के साथ पंक्तिबद्ध कर सकते हैं और उन सभी को एक साथ सम्मिलित कर सकते हैं जो वास्तव में बहुत शक्तिशाली है क्योंकि यह बहुत तेज़ है। ViewController.swift आपको यह कैसे करना है, इसका एक उदाहरण भी दिखाता है। आप जो वास्तव में कर रहे हैं, वह 'sqlAndParams' नामक शब्दकोशों का एक सरणी बना रहा है, इस स्ट्रिंग में अपने कुंजीशब्दों को दो कुंजी 'SQL' के साथ स्ट्रिंग सीक्वल स्टेटमेंट या क्वेरी के लिए, और 'PARAMS' जो केवल देशी वस्तुओं का एक सरणी है, SQLite बनाएँ उस क्वेरी के लिए समझता है। प्रत्येक 'sqlParams' जो सीक्वेल क्वेरी प्लस मापदंडों का एक व्यक्तिगत शब्दकोश है, फिर 'sqlAndParams' एरे में संग्रहीत किया जाता है। एक बार जब आप यह सरणी बना लेते हैं, तो आप कॉल करते हैं।

    let status = db.executeTransaction(sqlAndParams)
    if(status)
    {
        //Read Table AppInfo into an Array of Dictionaries for the above Transactions
        let results = db.getRecordsForQuery("select * from AppInfo ")
        NSLog("Results = \(results)")
    }

इसके अलावा सभी निष्पादन योग्य और getRecordsForQuery तरीके SQL क्वेरी के लिए सरल स्ट्रिंग और क्वेरी द्वारा आवश्यक पैरामीटर के लिए एक सरणी के साथ किया जा सकता है।

    let sql : String = "insert into AppInfo (name,value,descrip) values(?,?,?)"
    let params : Array = ["SQLiteDemo","1.0.0","unencrypted"]
    let status = db.executeStatement(sql, withParameters: params)
    if(status)
    {
        //Read Table AppInfo into an Array of Dictionaries for the above Transactions
        let results = db.getRecordsForQuery("select * from AppInfo ")
        NSLog("Results = \(results)")
    }

एक ऑब्जेक्टिव-सी संस्करण भी मौजूद है और इसे उसी SQLDataAccess कहा जाता है, इसलिए अब आप ऑब्जेक्टिव-सी या स्विफ्ट में अपना सीक्वल लिखना चुन सकते हैं। इसके अलावा SQLDataAccess SQLCipher के साथ भी काम करेगा, वर्तमान कोड इसके साथ काम करने के लिए अभी तक सेटअप नहीं है, लेकिन यह करना बहुत आसान है, और यह कैसे करना है इसका एक उदाहरण SQLDataAccess के Objective-C संस्करण में वास्तव में है।

SQLDataAccess एक बहुत तेज़ और कुशल वर्ग है, और इसका उपयोग CoreData के स्थान पर किया जा सकता है जो वास्तव में SQLite का उपयोग करता है क्योंकि यह CoreData के साथ आने वाले सभी CoreData कोर डेटा अखंडता दोष क्रैश के बिना अंतर्निहित डेटा स्टोर है।


-1

आप आसानी से एकल टन वर्ग का उपयोग करके स्विफ्ट के साथ SQLite को कॉन्फ़िगर कर सकते हैं।

देखें

https://github.com/hasyapanchasara/SQLite_SingleManagerClass

डेटाबेस बनाने की विधि

func methodToCreateDatabase() -> NSURL?{} 

डेटा डालने, अपडेट करने और हटाने का तरीका

func methodToInsertUpdateDeleteData(strQuery : String) -> Bool{}

डेटा का चयन करने की विधि

func methodToSelectData(strQuery : String) -> NSMutableArray{}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.