Saving Offline data into CB Lite 2.0 - ios

issue : ( CB Lite 2.0 , Swift)
Registration screen which has name, email and dob and want to save in couchbase lite.
everytime user-filled form with these fields I want to store in local CB Lite DB
After that i want to fetch all record store in the cb lite.
Issue is :
Created a document
stored name , emal and dob in swift dictionary and tried to save and it stores but everytime i fetch it shows only one , not other user information.
Kinldy help me on this.
Raised Query on Couchbase Forum :
https://forums.couchbase.com/t/saving-offline-data-into-cb-lite-2-0/17877?u=st.shubh.tiwari

This is the way i called by taking one sample notification and checked its working :
let dict = [
"alert": "push notification.. (5)",
"badge": 1,
"sound": "default"
] as [String : Any]
var notificationArray = [Dictionary<String,Any>]()
let notiDict = CouchDBHelper.fetchDocumentByDocId(documentID: Constants.notificationDocument)
if let notiArray = notiDict["notification"] as? [Dictionary<String,Any>] {
notificationArray = notiArray
}
notificationArray.append(dict)
CCouchDBHelper.insertNotificationData(data: notificationArray, doc_id: Constants.notificationDocument)
objNotifcationSource = notificationArray
objNotificationTable.reloadData()
public func insertNotificationData(data:Any?,doc_id:String)
{
//let sharedInstance = CouchbaseAdapter.sharedInstance
let doc = MutableDocument(id: doc_id)
doc.setValue(data, forKey: "notification")
do {
try database.saveDocument(doc)
//try sharedInstance.database.saveDocument(doc)
print("Inserted Record :", data as! NSArray)
} catch let error as NSError {
print("Error in saving",error)
}
fetchDocumentByDocId(documentID: doc_id)
}

Related

Retrieving Data deep from Firebase Query (iOS, Swift 4)

So I have been developing my Job board application for a while now. I'm a total newbie to programming and swift. I wanted to allow my users to post jobs and view them and also apply for the jobs via the app. Similar to 'Freelancer' app. I am using Firebase for my database and the issue I have now is:
This is my Database Query :
"Users": {
"UserID" : {
"Region" : {
"autoID : {
"Job Title" : String
"Job Description" : String
"Company Name" : String
}
}
}
}
The thing is that I have to retrieve data from job details which is under autoID and UserID which always show an error - Cannot use multiple queryOrderedBy calls!
This is my retrieve function
func retrievePost() {
var ref: DatabaseReference!
ref = Database.database().reference()
let postDB = ref.child("Users")
postDB.queryOrdered(byChild: "Region").queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
let snapshotValue = snapshot.value as! [String:String]
let jobTitle = snapshotValue["Job Title"]!
let companyName = snapshotValue["Company Name"]!
let jobDesc = snapshotValue["Job Description"]!
let posted = post()
posted.jobTitle = jobTitle
posted.company = companyName
posted.jobDescription = jobDesc
self.jobsPosted.append(posted)
self.feedTable.reloadData()
}
}
The user should be able to post a job and other users should be able to view the jobs posted and also later edit and update it. Considering all these, What will be the solution ?
Will these be possible in firebase ?
Thanks in Advance!

How to fetch the inbox from email agent in swift/objective c using mailcore framework or Any framework?

Step 1: Link (https://github.com/MailCore/MailCore2)
Step 2: I have added mailcore-framework in my project
Step 3: pod install for UICKeyChainStore in my project done
Step 4: Send mail successfully using MCOSMTPSession, MCOMessageBuilder.
Step 5: My problem is that I am not able to fetch using mailcore. Is there any other framework for fetching mail (inbox)?
Sorry for late answer. I have two apps in the App Store, both of them use MailCore2, so I can explain you a thing or two about that.
Of course you can fetch the emails with MailCore2, this is the code. If you have any other doubt with MailCore2 write about that, I will try to find the answer.
var imapsession:MCOIMAPSession = MCOIMAPSession()
func prepareImapSession()
{
// CONFIGURE THAT DEPENDING OF YOUR NEEDS
imapsession.hostname = imapHostname // String
imapsession.username = userName // String
imapsession.password = password // String
imapsession.port = portIMAP // UInt32 number
imapsession.authType = MCOAuthType.saslLogin
imapsession.connectionType = MCOConnectionType.TLS
}
func useImapWithUIDS()
{
// There is more than one option here, explore depending of your needs
let requestKind : MCOIMAPMessagesRequestKind = .headers
let folder : String = "INBOX"
// HERE ALSO EXPLORE DEPENDING OF YOUR NEEDS, RANGE IT IS THE RANGE OF THE UIDS THAT YOU WANT TO FETCH, I SUGGEST TO YOU TO CHANGE THE // NUMBER ONE IF YOU HAVE A LOWER BOUND TO FETCH EMAIL
let uids : MCOIndexSet = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX))
let fetchOperation = imapsession.fetchMessagesOperation(withFolder: folder, requestKind: requestKind, uids: uids)
fetchOperation?.start
{ (err, msg, vanished) -> Void in
if (err != nil)
{
error = err
NSLog((err?.localizedDescription)!)
}
else
{
guard let msgs = msg as? [MCOIMAPMessage]
else
{
print("ERROR GETTING THE MAILS")
return
}
for i in 0..<msgs.count
{
// THE SUBJECT
let subject = msgs[i].header.subject
// THE uid for this email. The uid is unique for one email
let uid = msgs[i].uid
// The sequenceNumber like the nomber say it is the sequence for the emails in the INBOX from the first one // (sequenceNumber = 1) to the last one , it not represent always the same email. Because if you delete one email then //next one will get the sequence number of that email that was deleted
let sequenceNumber = msgs[i].sequenceNumber
}
}
}
// MARK: - EXTRACT THE CONTENT OF ONE EMAIL, IN THIS FUNCTION YOU NEED THE uid, THE UNIQUE NUMBER FOR ONE EMAIL
func useImapFetchContent(uidToFetch uid: UInt32)
{
let operation: MCOIMAPFetchContentOperation = imapsession.fetchMessageOperation(withFolder: "INBOX", uid: uid)
operation.start { (Error, data) in
if (Error != nil)
{
NSLog("ERROR")
return
}
let messageParser: MCOMessageParser = MCOMessageParser(data: data)
// IF YOU HAVE ATTACHMENTS USE THIS
let attachments = messageParser.attachments() as? [MCOAttachment]
// THEN YOU NEED THIS PROPERTIE, IN THIS EXAMPLE I TAKE THI FIRST, USE WHAT EVER YOU WANT
let attachData = attachments?.first?.data
// FOR THE MESSAGEPARSER YOU CAN EPLORE MORE THAN ONE OPTION TO OBTAIN THE TEXT
let msgPlainBody = messageParser.plainTextBodyRendering()
}
You can give https://github.com/snipsco/Postal a try. This is a framework which aims to provide simple access to common email providers.

NSBatchDeleteRequest causes Merge Conflict

I have an application that will sync with a server with data that can change daily. During the sync, I remove all the data for some entities and reload it with new data. I am using the following code:
func SyncronizeUserComments(theData : [[AnyHashable : Any]])
{
// Delete User Comments for this User and Connection
let commentRequest : NSFetchRequest<NSFetchRequestResult> = PT_UserComments.fetchRequest()
commentRequest.predicate = NSPredicate(format: "connection = %# AND user == %#", Global_CurrentConnection!, Global_CurrentUser!)
coreData.processDeleteRequest(request: commentRequest)
// ADD the Comments to CoreData
for index in 0..<theData.count {
let result : [AnyHashable : Any] = theData[index]
if let commentID = result["Comment_ID"] as? String, let commentText = result["Comment_Text"] as? String, let commentTitle = result["Comment_Title"] as? String
{
let newUserComment = PT_UserComments(context: coreData.persistentContainer.viewContext)
newUserComment.connection = Global_CurrentConnection
newUserComment.user = Global_CurrentUser
newUserComment.comment_ID = commentID
newUserComment.comment_Text = commentText
newUserComment.comment_Title = commentTitle
}
}
// Add the User Comments
print("Added New User Comments: \(theData.count)")
coreData.saveContext()
}
func processDeleteRequest(request : NSFetchRequest<NSFetchRequestResult>)
{
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
deleteRequest.resultType = .resultTypeObjectIDs
do {
let result = try coreData.persistentContainer.viewContext.execute(deleteRequest) as? NSBatchDeleteResult
let objectIDArray = result?.result as? [NSManagedObjectID]
let changes = [NSDeletedObjectsKey : objectIDArray]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes as Any as! [AnyHashable : Any], into: [coreData.persistentContainer.viewContext])
} catch {
fatalError("Fatal Error Deleting Data: \(error)")
}
coreData.saveContext()
}
When I call coreData.saveContext() I will get a Merge Conflict against the deleted data.
In reading about CoreData and the NSBatchDeleteRequest, this deletes at the SQL LITE level and bypasses the in memory cache.
The only way I have been able to get this to work is by setting:
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
Is this correct, or am I doing something wrong? I am also setting this merge policy in my saveContext() in the Core Data Stack.
I just spent hours debugging the same issue, hopefully this can help someone.
The problem is that NSManagedObjectContext.mergeChanges(fromRemoteContextSave:, into:) updates the managed object context but does not update the row cache version number of the deleted objects relationships to match the updated version number (Z_OPT) in the database file, causing a mismatch at time of the save.
If you're using NSErrorMergePolicyType this will cause the next save to fail, (or even a later one when the relationships become flagged for save), even though everything but the version numbers match. I've not seen this mentioned in the related docs or WWDC video, but I guess Apple assumed people would always pick a non-default merge policy.
So picking NSMergeByPropertyStoreTrumpMergePolicy solves it, as mentioned in the question, but you might not want this policy for all your save operations. To avoid that I ended up writing a custom merge policy that only resolves version mismatches. The code is below (this is untested Swift as I originally wrote in Obj-C, but should be equivalent):
//Configure the merge as below before saving
context.mergePolicy = AllowVersionMismatchMergePolicy(merge: .errorMergePolicyType)
//...
//The custom merge policy
class AllowVersionMismatchMergePolicy: NSMergePolicy {
override func resolve(optimisticLockingConflicts list: [NSMergeConflict]) throws {
do {
//if the default resolve worked leave it alone
return try super.resolve(optimisticLockingConflicts: list)
} catch {
//if any of the conflict is not a simple version mismatch (all other keys being equal), fail
let hasValueConflict = list.contains { conflict -> Bool in
//compare object and row cache
if let objectSnapshot = conflict.objectSnapshot as NSObject?,
let cachedSnapshot = conflict.cachedSnapshot as NSObject? {
return !objectSnapshot.isEqual(cachedSnapshot)
}
//compare row cache and database
if let cachedSnapshot = conflict.cachedSnapshot as NSObject?,
let persistedSnapshot = conflict.persistedSnapshot as NSObject? {
return !cachedSnapshot.isEqual(persistedSnapshot)
}
//never happens, see NSMergePolicy.h
return true
}
if hasValueConflict {
throw error
}
//Use store rollback merge policy to resolve all the version mismatches
return try NSMergePolicy.rollback.resolve(optimisticLockingConflicts: list)
}
}
}

How to find out how many days have passed since an iOS app was opened the first time by a specific user/device?

I created an iOS app and would like to give the users the opportunity to use the app for free for 30 days since the app was installed and started the very first time.
After these 30 days I'd like to turn off most functionality. The only way to retain full functionality is to login in with username and password which the user can register for on a dedicated website.
My problem is:
When the app was started the very first time, I'd like store a unique identifier and a timestamp of this moment on a remote server. Then I'd know when 30 days have passed for this unique id.
Unfortunately, it seems like the only uuid-like identifier on iOS is identifierForVendor. According to the docs, when the user removes all apps from the same vendor of the app and then reinstalls them, the uuid changes. Since this uuid would not match the one I stored to the database on my remote server, the user would be able to re-use the app although 30 days had passed.
From the docs:
The uuid on iOS uses the identifierForVendor property. It is unique to
the device across the same vendor, but will be different for different
vendors and will change if all apps from the vendor are deleted and
then reinstalled. See the official Apple docs.
The UUID will be the same if app is restored from a backup or iCloud
as it is saved in preferences. Users using older versions of this
plugin will still receive the same previous UUID generated by another
means as it will be retrieved from preferences.
My question is:
Is there a way to find out how many days have passed since the user opened the app the very first time, even if he deletes/reinstalls all apps made by me?
Note: Since I am using Phonegap/Cordova, a Cordova-compatible solution would be welcome but a native Swift/Objective-C solution would be ok too.
Your app can store it's own unique ID (from a server or randomly generated perhaps) and/or a date-stamp in the iOS device's keychain. The keychain is not cleared when an app is deleted from a device.
See Apple's Keychain services programming guide.
What about NSUbiquitousKeyValueStore?
// Use `NSUbiquitousKeyValueStore`
let iCloudKeyStore: NSUbiquitousKeyValueStore? = NSUbiquitousKeyValueStore()
let isMyAppInstalled = true
iCloudKeyStore?.setBool(isMyAppInstalled, forKey: "isMyAppInstalled")
iCloudKeyStore?.synchronize()
If You can Create a webService to catch and Store Device ID's on a Sqlite table, here is the Solution:
You can get Device ID like this:
let DID = UIDevice.currentDevice().identifierForVendor!.UUIDString
print("Device ID is : \(DID)")
and then send this ID to your webSerivce like this:
on AppDelegate put this :
internal static var DeviceList:[StructID] = []
then Create a Swift Class with name StructID, like this :
import Foundation
class StructID{
internal var id:Int!
internal var DevieID:String!
internal var AllowInstall:String!
internal var InstalledTime:String!
internal var InstallCount:String!
}
then on Your FirstViewController You can send and store many data included how many this id installed this app or when is the first install or is this id alowed tho use this app? or anything you want !
let IDs = StructID()
IDs.DevieID = DID
IDs.AllowInstall = AllowInstall // <declare it yourself
IDs.InstalledTime = InstalledTime // <declare it yourself
IDs.InstallCount = InstallCount // <declare it yourself
var dictionary = Dictionary<String, AnyObject>()
dictionary["id"] = IDs.id
dictionary["DevieID"] = IDs.DevieID
dictionary["AllowInstall"] = IDs.AllowInstall
dictionary["InstalledTime"] = IDs.InstalledTime
dictionary["InstallCount"] = IDs.InstallCount
let url = NSURL(string: "http://www.YourWebAddress.com/service.php?action=insert")
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.timeoutInterval = NSTimeInterval(10)
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions(rawValue: 0))
request.HTTPBody = jsonData
} catch {
print("json data error")
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (NSData, response, error) -> Void in
let id = String (data: NSData!, encoding: NSUTF8StringEncoding)
DeviceList.id = Int(id!) // <= its id column of your table
AppDelegate.DeviceList.append(IDs) // <= it the Device id Your are sending
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.navigationController?.popToRootViewControllerAnimated(true)
})
}
task.resume()
}
and your php code on your webService:
function getConnection () {
$servername = "localhost";
$username = "YourDatabseName_db";
$password = "Password";
$dbname = "YourDatabseName_db";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
return $conn;
}
$action = $_GET["action"];
if ($action == "insert") {
$conn = getConnection();
$jsonString = file_get_contents('php://input');
$data = json_decode($jsonString, true);
$DeviceID = $data["DeviceID"];
$AllowInstall = $data["AllowInstall"];
$InstalledTime = $data["InstalledTime"];
$InstallCount = $data["InstallCount"];
$sql = "INSERT INTO `YourDatabase_db`.`YourTableName` (`DeviceID`, `AllowInstall`, `InstalledTime `, `InstallCount `) VALUES ('$DeviceID', '$AllowInstall', '$InstalledTime', '$InstallCount')";
if (mysqli_query($conn, $sql)){
$last_id = mysqli_insert_id($conn);
echo $last_id;
} else {
echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
finally When Your app Stars each time, you an Check all the Conditions and do what ever you want...
for readig Back from php put it on your webservice php :
if ($action == "selectgeneral") {
$conn = getConnection();
$sql = "SELECT * FROM yourtablename";
$result = $conn->query($sql);
$output = array();
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$record = array();
$record["id"] = $row["id"];
$record["DevieID"] = $row["DevieID"];
$record["AllowInstall"] = $row["AllowInstall"];
$record["InstalledTime"] = $row["InstalledTime"];
$record["InstallCount"] = $row["InstallCount"];
array_push($output, $record);
}
} else {
echo "0 results";
}
$conn->close();
echo json_encode($output);
and if you want to read your data from your php :
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {(NSData, response, error) -> Void in
do {
let records = try NSJSONSerialization.JSONObjectWithData(NSData!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
for record in records {
let record = StructID()
record.id = Int(record["id"] as! String)
record.DevieID = record["DevieID"] as! String
record. AllowInstall = record["AllowInstall"] as! String
record.InstalledTime = Int(record["InstalledTime"] as! String)
record.InstallCount = Int(record["InstallCount"] as! String)
AppDelegate.DeviceID.append(record)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableViewNote.reloadData()
})
}
catch {
print("Json Error")
}
}
task.resume()
Sorry if its a little complicated.

How to retrieve emails from iPhone Contacts using swift?

I am new to swift . I used APAdressBook Framework for retrieving contacts in iPhone .Every thing working fine up to IOS 8.4 but when checked in IOS 9 of Simulator and iPhone devices it is not accessing contacts and even it not showing alert message like would you like to access contacts any one can face this type of problem if yes please give me your valuable answer?
Apple Inc. introduce Contacts.framework from iOS 9. So, it would be better use this framework to retrieve contacts.
Here is way to fetch email or whole contact from Contacts app.
Add Contacts.framework to your project.
Create or add new file of type header and give name like yourProjectName-Bridging-Header.h write #import <Contacts/Contacts.h> statement into file and save and set appropriate path of this file from build setting.
Now create method
func getAllContacts() {
let status = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts) as CNAuthorizationStatus
if status == CNAuthorizationStatus.Denied {
let alert = UIAlertController(title:nil, message:"This app previously was refused permissions to contacts; Please go to settings and grant permission to this app so it can use contacts", preferredStyle:UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title:"OK", style:UIAlertActionStyle.Default, handler:nil))
self.presentViewController(alert, animated:true, completion:nil)
return
}
let store = CNContactStore()
store.requestAccessForEntityType(CNEntityType.Contacts) { (granted:Bool, error:NSError?) -> Void in
if !granted {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// user didn't grant access;
// so, again, tell user here why app needs permissions in order to do it's job;
// this is dispatched to the main queue because this request could be running on background thread
})
return
}
let arrContacts = NSMutableArray() // Declare this array globally, so you can access it in whole class.
let request = CNContactFetchRequest(keysToFetch:[CNContactIdentifierKey, CNContactEmailAddressesKey, CNContactBirthdayKey, CNContactImageDataKey, CNContactPhoneNumbersKey, CNContactFormatter.descriptorForRequiredKeysForStyle(CNContactFormatterStyle.FullName)])
do {
try store.enumerateContactsWithFetchRequest(request, usingBlock: { (contact:CNContact, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
let arrEmail = contact.emailAddresses as NSArray
if arrEmail.count > 0 {
let dict = NSMutableDictionary()
dict.setValue((contact.givenName+" "+contact.familyName), forKey: "name")
let emails = NSMutableArray()
for index in 0...arrEmail.count {
let email:CNLabeledValue = arrEmail.objectAtIndex(index) as! CNLabeledValue
emails .addObject(email.value as! String)
}
dict.setValue(emails, forKey: "email")
arrContacts.addObject(dict) // Either retrieve only those contact who have email and store only name and email
}
arrContacts.addObject(contact) // either store all contact with all detail and simplifies later on
})
} catch {
return;
}
}
}
Call this method where you want self.getAllContacts()
And when you want to retrieve
for var index = 0; index < self.arrContacts.count; ++index {
let dict = self.arrContacts[index] as! NSDictionary
print(dict.valueForKey("name"))
print(dict.valueForKey("email"))
}

Resources