How to encrypt and decrypt using 'FMDB/SQLCipher' in Swift? - ios

I have used FMDB to create a SQLite database in Swift. But now I want to encrypt it. So can anyone please help me with the Swift version of encrypting and decrypting SQLite database using 'FMDB/SQLCipher'? I was not able to find a good tutorial to understand this.

Below is a sample code that sets a key on a database which is a FMDatabase object. You have to use the setKey() method in order to access an encrypted database. I have also written a wrapper over FMDB library which will make your life easier dealing with encrypted databases.
Here it is : https://github.com/SagarSDagdu/SDDatabase/
It also has ample amount of documentation and example code.
func executeUpdate(onDatabase database:FMDatabase, withStatement statement:String, values: [Any]?) -> Bool {
var success:Bool = false
do {
database.logsErrors = self.loggingEnabled
if let key = self.dbPassKey { //Use your key here
database.setKey(key)
}
try database.executeUpdate(statement, values:values)
success = true
}
catch {
print("Error in \(#function) with query: \(statement), error : \(error)")
}
return success
}

Related

How to filter data from Sqlite IOS Swift?

Hi i am using following library for sqlite implementation in my project.
https://github.com/stephencelis/SQLite.swift
In my sqlite i am storing huge amount of data from there i am filtering my values. This is my tried code.
let user = self.usersTable.filter(self.id == textfild.text!)
do {
for row in try self.database.prepare(user) {
print("id: \(row[self.id]), code: \(row[self.email])")
}
}catch {
print(error)
}
this code is working if the two values are same ex: ( 171(self.id value) == 171 )(textfield value) but i am looking for if i enter "17" it should shows all related data in sqlite.
user[self.id].localizedCaseInsensitiveContains(textfild.text) i tried this but its not working.

How to access a specific field from Cloud FireStore Firebase in Swift

Here is my data structure:
I have an ios app that is attempting to access data from Cloud Firestore. I have been successful in retrieving full documents and querying for documents. However I need to access specific fields from specific documents. How would I make a call that retrieves me just the value of one field from Firestore in swift? Any Help would be appreciated.
There is no API that fetches just a single field from a document with any of the web or mobile client SDKs. Entire documents are always fetched when you use getDocument(). This implies that there is also no way to use security rules to protect a single field in a document differently than the others.
If you are trying to minimize the amount of data that comes across the wire, you can put that lone field in its own document in a subcollection of the main doc, and you can request that one document individually.
See also this thread of discussion.
It is possible with server SDKs using methods like select(), but you would obviously need to be writing code on a backend and calling that from your client app.
This is actually quite simple and very much achievable using the built in firebase api.
let docRef = db.collection("users").document(name)
docRef.getDocument(source: .cache) { (document, error) in
if let document = document {
let property = document.get(field)
} else {
print("Document does not exist in cache")
}
}
There is actually a way, use this sample code provided by Firebase itself
let docRef = db.collection("cities").document("SF")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let property = document.get('fieldname')
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
}
I guess I'm late but after some extensive research, there is a way in which we can fetch specific fields from firestore. We can use the select keyword, your query would be somthing like (I'm using a collection for a generalized approach):
const result = await firebase.database().collection('Users').select('name').get();
Where we can access the result.docs to further retrieved the returned filtered result. Thanks!
//this is code for javascript
var docRef = db.collection("users").doc("ID");
docRef.get().then(function(doc) {
if (doc.exists) {
//gives full object of user
console.log("Document data:", doc.data());
//gives specific field
var name=doc.get('name');
console.log(name);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});

Prevent Realm from writing JSON twice

I'm new to Realm and iOS. I'm working on an app(written in Swift) that has a feature for the user to search for golf courses. I have a JSON file with roughly 18K courses in it. So I wanted to use Realm so I can quickly search through these courses in my app without it slowing down the user experience. I was able to get my JSON file written to the Realm Browser and can retrieve and search through the items, which has made it a LOT faster.
The problem I'm is I have the code in my App Delegate because I wanted to send the JSON items to my Realm Browser upon the app's launch. But if the app is started again then it writes the JSON file again, which creates duplicate golf courses in my Realm Browser.
Any suggestions on how I should do this so I can write the JSON file to the browser without getting duplicates each time the app is launched?
Thanks!
My code for writing my JSON file to my Realm Browser:
let dataManager = DataManager.getGolfCoursesFromFileWithSuccess { (data) -> Void in
let json = JSON(data: data)
if let courseArray = json.array {
for course in courseArray {
let golfCourseName: String? = course["biz_name"].string
let city: String? = course["e_city"].string
let state: String? = course["e_state"].string
if golfCourseName != nil {
let course = Course()
course.name = golfCourseName!
course.city = city!
course.state = state!
let realm = try! Realm()
try! realm.write {
realm.add(course)
}
}
}
}
}
Just check to see if the data is stored already.
I.e.
if try! Realm().objects(GolfCourse).count == 0 {
// your loading code here.
}
I figured it out. Because this was a data set that I wanted the user to have when they initially start using the app I learned how to bundle a Realm file with this data and put the file directly in my Xcode project. I then configured this file using the method:
"NSBundle.mainBundle().pathForResource("MyBundledData", ofType:"realm")"

Cloudant does not not store object data sent via Bluemix "Data for iOS 8"

I am trying to store a simple object (a custom class that has two String properties) in a Cloudant DB from an iOS App. I am making use of the Bluemix iOS SDK, specifically "Data for iOS 8". So far I am trying to apply the samples for the Swift programming language from the IBM Bluemix documentation.
The code to store an object is from the tutorials and has been only slightly adapted, if at all. The code below is contained in a function that is called when a text field's edit is done.
var remoteStore:CDTStore!
// initialize an instance of the IMFDataManager
let manager:IMFDataManager = IMFDataManager.sharedInstance()
let name = "pricingdb"
var testData = TestData(firstName: "aaaa", lastName: "bbbbb")
// Create remote store
manager.remoteStore(name, completionHandler: { (createdStore:CDTStore!, error:NSError!) -> Void in
if nil != error {
//Handle error
} else {
remoteStore = createdStore
println("Successfully created store: \(remoteStore.name)")
// Register class with remote store
remoteStore.mapper.setDataType("TestData", forClassName: NSStringFromClass(TestData.classForCoder()))
// Actually save the object to Bluemix
remoteStore.save(testData, completionHandler: { (savedObject:AnyObject!, error:NSError!) -> Void in
if nil != error {
//Save was not successful, handler received an error
println("Error: \(error)")
} else {
// Use the result
println("Saved revision: \(savedObject)")
}
})
}
})
The Cloudant database I want to store to exists. I can connect to the Datastore and the object is as well saved, the console output is:
HTTP_Status: 201
JSON Body: {
id = 6dfde55449915faa92c471bd0ecd89d6;
ok = 1;
rev = "1-419dfa2a14026c4c18545723e8f990fa";
}
Saved revision: <pricingtester.TestData: 0x7f91f1c6e2f0>
However, when looking at the JSON Body above I would expect to see the object data in there and, even if it wouldn't/shouldn't show there, I would expect to see it in the database entry that was created. But the corresponding database entry when checking the Cloudant dashboard is as follows:
{
"_id": "6dfde55449915faa92c471bd0ecd89d6",
"_rev": "1-419dfa2a14026c4c18545723e8f990fa",
"#datatype": "TestData"
}
What could I be missing?
A related question came up:
In the code above, the store is always created. If it exists, it is not recreated, but a reference to that store is made. If I know the store exists, which it does, how can I obtain a reference to that store without trying to first create it?
Can you provide the source code for the TestData class? For swift classes, String must currently use the NSString (ObjC) instead of the Swift String (e.g. var make:NSString)

Steps to setting up relational database (sqlite) in swift

I am working on an iOS app and I want to set up a relational database for it. I read that SQLite is a good database to use. I'm making the app in Swift. I've looked at several tutorials but it seems like all the ones that I found have the DBManager class or libraries in objective-c. Therefore, I would need a wrapper for the db class. I'm not really sure how the wrapper works and how I would be calling objective-c methods using swift syntax.
I was wondering if someone could help clarify the whole process for this from creating the database file and adding it to your xcode project to using objective-c libraries with swift syntax in order to run queries against the database file.
Also, is it worth it to just use Core Data which seems easier to use instead?
Objective-C tutorials are still more-or-less relevant, but obviously won't bring Swift-specific niceties into the fold (nor does FMDB, currently, as recommended by another commenter). I ended up writing SQLite.swift to utilize some of the more interesting aspects of Swift (type-safety and generics, optionals):
https://github.com/stephencelis/SQLite.swift
SQLite.swift provides compile-time safety/confidence, and removes the need for a lot of error handling. Statements and expressions are built in Swift proper, so runtime SQL syntax errors are unlikely.
See the documentation for more information on creating the database file and where to store it (depending on your needs):
https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md#connecting-to-a-database
As far as Core Data is concerned, it (like most Apple libraries at the time of this answer) doesn't take advantage of Swift, but has a rich legacy and may be the way to go, especially for a smaller, persistent object graph. However, if you want control over a relational database, or if you plan on storing a large dataset that changes frequently, you may become frustrated with Core Data (and the domain-specific knowledge you'll need to attain),
I have myself followed this step by step and well explained tutorial by techtopia.
http://www.techotopia.com/index.php/Swift_iOS_8_Database_Implementation_using_SQLite
http://www.techotopia.com/index.php/An_Example_SQLite_based_iOS_8_Application_using_Swift_and_FMDB
It uses FMDB wrapper.
Creating the Database and Table
override func viewDidLoad() {
super.viewDidLoad()
let filemgr = NSFileManager.defaultManager()
let dirPaths =
NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
.UserDomainMask, true)
let docsDir = dirPaths[0] as! String
databasePath = docsDir.stringByAppendingPathComponent(
"contacts.db")
if !filemgr.fileExistsAtPath(databasePath as String) {
let contactDB = FMDatabase(path: databasePath as String)
if contactDB == nil {
println("Error: \(contactDB.lastErrorMessage())")
}
if contactDB.open() {
let sql_stmt = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
if !contactDB.executeStatements(sql_stmt) {
println("Error: \(contactDB.lastErrorMessage())")
}
contactDB.close()
} else {
println("Error: \(contactDB.lastErrorMessage())")
}
}
}
The code in the above method performs the following tasks:
-Identifies the application’s Documents directory and constructs a path to the contacts.db database file.
-Creates an NSFileManager instance and subsequently uses it to detect if the database file already exists.
-If the file does not yet exist the code creates the database by creating an FMDatabase instance initialized with the database file path. If the database creation is successful it is then opened via a call to the open method of the new database instance.
-Prepares a SQL statement to create the contacts table in the database and executes it via a call to the FMDB executeStatements method of the database instance.
-Closes the database.
SAVE DATA TO DATABASE
#IBAction func saveData(sender: AnyObject) {
let contactDB = FMDatabase(path: databasePath as String)
if contactDB.open() {
let insertSQL = "INSERT INTO CONTACTS (name, address, phone) VALUES ('\(name.text)', '\(address.text)', '\(phone.text)')"
let result = contactDB.executeUpdate(insertSQL,
withArgumentsInArray: nil)
if !result {
status.text = "Failed to add contact"
println("Error: \(contactDB.lastErrorMessage())")
} else {
status.text = "Contact Added"
name.text = ""
address.text = ""
phone.text = ""
}
} else {
println("Error: \(contactDB.lastErrorMessage())")
}
}
FETCH DATA FROM DATABASE
#IBAction func findContact(sender: AnyObject) {
let contactDB = FMDatabase(path: databasePath as String)
if contactDB.open() {
let querySQL = "SELECT address, phone FROM CONTACTS WHERE name = '\(name.text)'"
let results:FMResultSet? = contactDB.executeQuery(querySQL,
withArgumentsInArray: nil)
if results?.next() == true {
address.text = results?.stringForColumn("address")
phone.text = results?.stringForColumn("phone")
status.text = "Record Found"
} else {
status.text = "Record not found"
address.text = ""
phone.text = ""
}
contactDB.close()
} else {
println("Error: \(contactDB.lastErrorMessage())")
}
}
You could use the sqlite wrapper included in this project. It's written in Objective-C but it can easily be used from within Swift.
Yet another SQLite wrapper for Swift 3: http://github.com/groue/GRDB.swift
It provides:
An API that will look familiar to users of the famous Objective-C FMDB (https://github.com/ccgus/fmdb)
A low-level SQLite API that leverages the Swift standard library.
A pretty Swift query interface for SQL-allergic developers
Support for the SQLite WAL mode, and concurrent database access for extra performance
A Record class that wraps result sets, eats your custom SQL queries for breakfast, provides persistence operations, and changes tracking.
Swift type freedom: pick the right Swift type that fits your data. Use Int64 when needed, or stick with the convenient Int. Store and read NSDate or NSDateComponents. Declare Swift enums for discrete data types. Define your own database-convertible types.
Database migrations
Speed: https://github.com/groue/GRDB.swift/wiki/Performance

Resources