apollo-ios How to cache data on disk? - ios

I need cache my data on disk for offline view, I found ApolloSQLite in the apollo-ios source, but I can't find any documents of ApolloSQLite(I also tried Google search).
Environment:
Xcode 10.1
macOS 10.14.3
CocoaPods 1.5.3
Apollo (0.9.5)
SQLite.swift (0.11.5)
Too many errors coming after pod install:
pod 'Apollo'
pod 'Apollo/SQLite'

When I use CocoaPods 1.5.3, missing the source Apollo/Core after pod install, it causes the errors. I've fixed it by upgrade CocoaPods to 1.6.0.
BTW, the original question is how to use ApolloSQLite? Because I've not found any documents for ApolloSQLite. After too many search & query, I list my steps as below for other people for help:
use CocoaPods for manage the libs:
pod 'Apollo'
pod 'Apollo/SQLite'
need a file path to save the sqlite file which use for cache data. Paste my codes for refer:
func temporarySQLiteFileURL() -> URL {
let applicationSupportPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!
let dbPath = applicationSupportPath + "/com.[special name].cache"
if !FileManager.default.fileExists(atPath: dbPath) {
try? FileManager.default.createDirectory(atPath: dbPath, withIntermediateDirectories: true, attributes: nil)
}
let url = URL(fileURLWithPath: dbPath)
return url.appendingPathComponent("db.sqlite3")
}
configure the ApolloClient:
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10
let url = URL(string: self.graphQLApiAddress!)!
let networkTransport = HTTPNetworkTransport(url: url, configuration: configuration)
let cache = try? SQLiteNormalizedCache(fileURL: temporarySQLiteFileURL())
let store = ApolloStore(cache: cache ?? InMemoryNormalizedCache())
self.apolloClient = ApolloClient(networkTransport: networkTransport, store: store)

Related

How can I make folders in my custom directory and create create a folder in /myapp/documents in advance(when I build the app)?

I'm making a vocabulary application for iOS and ipadOS. The structure is
Folders(IELTS, TOPFL, etc) -> Vocabularies(Cambridge IELTS, Oxford IELTS, etc) -> words(play, sleep, etc)
The Vocabularies file will be .txt file, so I can make it like
["word1" : "meaning1"], ["word1", "meaning2"], ....
And I want to make Folders file when users install the app.
So it would be my app/documents/folders
But when I install the app, it becomes my app/documents/, no folders.
Is there something like install script on iOS?
And the second question is when I create folder
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let docURL = URL(string: documentsDirectory)!
let dataPath = docURL.appendingPathComponent(String(AddNewFolder.text!)) // AddNewFolder is a Text Field
if !FileManager.default.fileExists(atPath: dataPath.absoluteString) {
do {
try FileManager.default.createDirectory(atPath: dataPath.absoluteString, withIntermediateDirectories: true, attributes: nil)
} catch {
print(error.localizedDescription);
}
}
How can I create new folder in myapp/documents/folders, not /myapp/documents?
Third question is about UIKit vs SwiftUI. What is faster and what is easier to use?
And in SwiftUI, there are SwiftUI App and UIKit delegate and what is UIKit delegate?(Does that mean that I use UIKit in SwiftUI?)
I googled a whole week. The answer is
// make subdirectory "vocabFolder" if it doesn't exist
let VocabFolderPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("vocabFolder")
if !FileManager.default.fileExists(atPath: VocabFolderPath.absoluteString) {
try! FileManager.default.createDirectory(at: VocabFolderPath, withIntermediateDirectories: true, attributes: nil)
}
// create custom vocab folder
let CustomVocabFolderPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("vocabFolder/\(String(AddNewFolder.text!))")
if !FileManager.default.fileExists(atPath: CustomVocabFolderPath.absoluteString) {
try! FileManager.default.createDirectory(at: CustomVocabFolderPath, withIntermediateDirectories: true, attributes: nil)
}
and to navigate a Simualtor device, execute
open 'xcrun simctl get_app_container booted BUNDLE_IDENTIFIER data' -a Finder

Where is a file stored in .documentDirectory?

I wrote a file in .documentDirectory in .userDomainMask:
do {
let fileManager = FileManager.default
let docs = try fileManager.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil, create: false)
let path = docs.appendingPathComponent("myName.txt")
let data = "Hai...!".data(using: .utf8)!
fileManager.createFile(atPath: path.absoluteString, contents: data, attributes: nil)
} catch {
// handle error
}
I have not gotten any errors or exceptions. It runs perfectly. But I can't see that file. Where can I find that file?
just add in target -> info -> custom iOS Target properties
Application supports iTunes file sharing - YES
and you will be able to see the folder you saved a file in Files app on your simulator.
Otherwise use print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)) to get a path to folder using Finder

SQlite Cipher IOS

This here i have shared to show that i have Sqlite file present in copy bundle resources : I am using Sqlitecipher in my iOS app when run my app in Simulator (offline) it shows all of the data successfully and every query works fine like (update,delete,insert) but when testing my app on device it doesn't shows up anything. Following way i tried it :
Saved Sqlite file in bundle
Copied Sqlite file from bundle to Document Directory
Delete app from Simulator and reset my Simulator but i am still facing the same issue. Kindly suggest solution ( its a Salesforce native App )
This is the code to get file from bundle to Document Directory in Appdelegate:`
func copyFile()
{
var documents: NSString
documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let bundlePath = NSBundle.mainBundle().pathForResource("LeadWork1", ofType: "sqlite")
print(bundlePath, "\n") //prints the correct path
let destPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first!
let fileManager = NSFileManager.defaultManager()
let fullDestPath = NSURL(fileURLWithPath: destPath).URLByAppendingPathComponent("LeadWork1.sqlite")
let fullDestPathString = fullDestPath.path
print(fullDestPathString)
print(fileManager.fileExistsAtPath(bundlePath!)) // prints true
if fileManager.fileExistsAtPath(bundlePath!) == true
{
print("File Exist")
}
else
{
do{
try fileManager.copyItemAtPath(bundlePath!, toPath: [enter image description here][1]fullDestPathString!)
}catch{
print("\n")
print(error)
}
}
let error = sqlite3_open(fullDestPathString!, &database)
if error != SQLITE_OK
{
print("Error while opening");
}
else
{
// print(fileForCopy)
print(destPath)
print("already open");
}
}`
Help will be appreciated!
Just Enable following :
Select Project -> Build Setting -> Architecture Tab - > Build Release to YES
Make sure to enable Both Debug and Release to YES.
It will solve your issue .

CoreData inside CocoaPods library

I've developed an iOS framework several months ago, and now I would like to use CocoaPods to develop and distribute it easily. Now I distribute it sending my .framework file, I know this is not the best way and because of that I would like to use CocoaPods.
My problem is, inside my framework I use CoreData and I cannot make it work with Pods.
If I get my old .framework and import it into my app project, everything works nice and CoreData works like a charm.
Digging into the issue, it seems that the Database.momd is not found into the bundle.
I'm going to attach the piece of code inside the framework that fails:
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle bundleWithIdentifier:#"kemmitorz.myFramework"] URLForResource:#"Database" withExtension:#"momd"];
// HERE modelURL RETURNS NIL with Pods
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
I know this could be caused by wrong framework configuration, or wrong Pods configuration, but I don't know what I'm missing.
Also, here is my myFramework.podspec file:
Pod::Spec.new do |s|
s.name = 'myFramework'
s.version = '0.1.0'
s.summary = 'A short description of myFramework.'
....
s.ios.deployment_target = '8.0'
s.source_files = 'myFramework/**/*.{h,m}'
s.frameworks = 'Foundation', 'Security', 'CFNetwork', 'CoreData'
s.library = 'icucore'
s.dependency 'SocketRocket'
s.dependency 'AFNetworking'
s.dependency 'OCMapper'
end
I've also tried to add {h,m,xcdatamodeld} to the type of source files unsuccessfully.
What I'm missing? Repeat, if I compile and import the framework on my own, everything works, so I suppose is something related with CocoaPods configuration.
It depends on the cocoapods version you are using, The recommended way to do it in 1.0.x is to add the s.resource_bundles with a list of resource files that should be included in the bundle Cocoapods resource_bundles, for example:
...
s.source_files = 'myFramework/**/*.{h,m}'
s.resource_bundles = {'myFramework' => ['myFramework/*.xcdatamodeld']}
...
And then use some class of your framework to get the bundle and the resource:
guard let bundleURL = NSBundle(forClass: FrameworkClass.self).URLForResource("myFramework", withExtension: "bundle") else { throw Error }
guard let frameworkBundle = NSBundle(URL: bundleURL) else { throw Error }
guard let momURL = frameworkBundle.URLForResource("Database", withExtension: "momd") else { throw Error }
Things can get a little tricky here, but if you use the right paths everything works as expected.
A little update for swift 5 as I had been struggling to get this to work.
In the podspec I needed to define the s.resource_bundles as
s.resource_bundles = {
'FrameworkNameHere' => ['FrameworkNameHere/**/*.{xcdatamodeld}']
}
and in code to get the managed object model
guard let bundleUrl = Bundle(for: self).url(forResource: "FrameworkName", withExtension: "bundle"),
let frameworkBundle = Bundle(url: bundleUrl),
let modelUrl = frameworkBundle.url(forResource: "CoreDataModelName", withExtension: "momd"),
let managedObjectModel = NSManagedObjectModel(contentsOf: modelUrl) else {
fatalError("Managed object model not found")
}
Although this seems to be failing my unit tests that were originally built explicitly using the frameworks bundle id. I am thinking an initialiser for my core data class that allows me to do one or the other based on unit test/ app environment may be the answer.

How to migrate a realm database to an app group?

Really excited about the recent addition of sharing Realm data between apps and extensions. The documentation details how to set the default realm to the app group directory, I've got that working.
Here's what I'm stuck on -- what's the best way to transfer the old database to the new location in the app group?
Based on #segiddins comment, I decided to go with moving the old database to the app group using NSFileManager:
let fileManager = NSFileManager.defaultManager()
//Cache original realm path (documents directory)
let originalDefaultRealmPath = RLMRealm.defaultRealmPath()
//Generate new realm path based on app group
let appGroupURL: NSURL = fileManager.containerURLForSecurityApplicationGroupIdentifier("group.AppGroup")!
let realmPath = appGroupURL.path!.stringByAppendingPathComponent("default.realm")
//Moves the realm to the new location if it hasn't been done previously
if (fileManager.fileExistsAtPath(originalDefaultRealmPath) && !fileManager.fileExistsAtPath(realmPath)) {
var error: NSError?
fileManager.moveItemAtPath(originalDefaultRealmPath, toPath: realmPath, error: &error)
if (error != nil) {
println(error)
}
}
//Set the realm path to the new directory
RLMRealm.setDefaultRealmPath(realmPath)
Hope this will help other reader.
As discussed in https://github.com/realm/realm-cocoa/issues/4490, you can set app group path with below code and use File Manager to move existing db as mention above.
var config = Realm.Configuration()
config.fileURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)!.appendingPathComponent(dbFilename)
Realm.Configuration.defaultConfiguration = config

Resources