static func realmConfig() -> Realm.Configuration {
var config = Realm.Configuration(schemaVersion: 6, migrationBlock: { (migration, oldSchemaVersion) in
/// Migration block. Useful when you upgrade the schema version.
})
config.fileURL = Bundle.main.url(forResource: "default", withExtension: "realm")!
print(config.fileURL)
let folderPath = config.fileURL!.deletingLastPathComponent().path
let lockPath = Bundle.main.url(forResource: "default.realm", withExtension: "lock")!.path
do {
try FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.none],ofItemAtPath: folderPath)
try FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.none],ofItemAtPath: lockPath)
} catch {
fatalError("Realm initialization failed, Error:\(error)")
}
return config
}
private static func realmInstance() -> Realm {
do {
let newRealm = try Realm(configuration: realmConfig())
return newRealm
} catch {
print(error)
fatalError("Unable to create an instance of Realm")
}
}
}
The realm .lock file is an under the hood file used only by realm. You will never need to work with that file directly or bundle it when using a bundled realm. All that's needed the the realm file itself, dragged into the XCode project.
Here's how to access a bundled Realm called MyBundledData.realm:
let config = Realm.Configuration(
// Get the URL to the bundled file
fileURL: Bundle.main.url(forResource: "MyBundledData", withExtension: "realm"),
// Open the file in read-only mode as application bundles are not writeable
readOnly: true)
// Open the Realm with the configuration
let realm = try! Realm(configuration: config)
that should be all that's needed
Try to add NSFileProtectionNone on parent directory
let realm = try! Realm()
// Get our Realm file's parent directory
let folderPath = realm.configuration.fileURL!.deletingLastPathComponent().path
// Disable file protection for this directory
try! FileManager.default.setAttributes([FileAttributeKey(rawValue: NSFileProtectionKey): NSFileProtectionNone],
ofItemAtPath: folderPath)
My iOS app is using Realm database
I want to copy or move the current default.realm database file to the new directory (App Group location) so that I can share it with Today Extension widget.
I tried as this post says (How to transfer Realm database to appgroups)
The core code is
let fileManager = FileManager.default
let originalPath = Realm.Configuration.defaultConfiguration.fileURL!
let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.myApp")!.appendingPathComponent("default.realm")
do{
try fileManager.replaceItemAt(appGroupURL, withItemAt: originalPath)
}
catch{
print("Error information: \(error)")
}
And I put this code inside Realm migration scope inside didFinishLaunchingWithOptions as below
To give you clearer picture where I'm using this code.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var config = Realm.Configuration(
schemaVersion: 1,
migrationBlock: { migration, oldSchemaVersion in
if (oldSchemaVersion < 1) {
let fileManager = FileManager.default
let originalPath = Realm.Configuration.defaultConfiguration.fileURL!
let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.myApp")!.appendingPathComponent("default.realm")
do{
try fileManager.replaceItemAt(appGroupURL, withItemAt: originalPath)
}
catch{
print("Error information: \(error)")
}
}
}
)
}
When I try this, my console says the file couldn't be saved.
Error Domain=NSCocoaErrorDomain Code=512 "The file “default.realm” couldn’t be saved in the folder “2EEADCEE-F9D9-44A8-BDED-B60A689656A2”." UserInfo={NSFileOriginalItemLocationKey=file:///Users/jm/Library/Developer/CoreSimulator/Devices/38334AE3-6648-402E-AC18-8252426002D6/data/Containers/Shared/AppGroup/2EEADCEE-F9D9-44A8-BDED-B60A689656A2/default.realm, ......
I heard copy / moving Realm database file should be done before opening the file, is this error related to that?
Thanks for your help and have a great day
Thank you #Jay for commenting which helped my find a way.
As he mentioned moving Realm DB file should be done before we call anything related to the Realm.
Originally I had a code inside of Realm migration so that it will run only once when the schema version is older,
but I moved it outside, top of the didFinishLaunchingWithOptions so now it works moving Realm DB file to the different directory.
Hope this helps somebody who's struggling.
let fileManager = FileManager.default
let originalPath = Realm.Configuration.defaultConfiguration.fileURL!
let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myApp")!.appendingPathComponent("default.realm")
if fileManager.fileExists(atPath: originalPath.absoluteString) {
do{
try fileManager.replaceItemAt(appGroupURL, withItemAt: originalPath)
print("Successfully replaced DB file")
}
catch{
print("Error info: \(error)")
}
} else {
print("File is not exist on original path")
}
var config = Realm.Configuration(
)
config.fileURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myApp")!.appendingPathComponent("default.realm")
// Tell Realm to use this new configuration object for the default Realm
Realm.Configuration.defaultConfiguration = config
// Now that we've told Realm how to handle the schema change, opening the file
// will automatically perform the migration
let realm = try! Realm()
Is there any way I can completely nuke everything from my Realm Cloud, including existing schema definitions?
There is a way to delete the Realms from the Realm Object Server.
Here's information I collected on a Realm Forums Post
Here's a link to the official docs.
This is super important though. The docs I am linking are for Docs 3.0. Self-hosting appears to be going away so the 3.16 Docs no longer include this information.
There are two steps
Remove server files
Remove all local files
These both have to be done or else Realm will try to re-sync itself and your data will never go away.
The first function deletes a Realm Cloud instance and if successful, deletes the local realm files.
//
//MARK: - delete database
//
func handleDeleteEverything() {
let realm = RealmService //Singleton that returns my realm cloud
try! realm.write {
realm.deleteAll()
}
guard let currentUser = SyncUser.current else {return}
let adminToken = currentUser.refreshToken!
let urlString = "https://your_realm.cloud.realm.io" //from RealmStudio upper right corner
let endPoint = "\(urlString)/realms/files/realm_to_delete"
let url = URL(string: endPoint)
var request = URLRequest(url: url!)
request.httpMethod = "DELETE"
request.addValue(adminToken, forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let err = error {
print("err = \(err.localizedDescription)")
return
}
print("Realm has been deleted")
self.deleteLocalRealmFiles() //remove local files
}
task.resume()
}
and then the function to remove the local files. This function is a bit different than what appears on the Realm Forums post with the addition of this function in Realm 4.2
try Realm.deleteFiles(for: config)
and the function that calls it
func deleteLocalRealmFiles() {
do {
let config = Realm.Configuration.defaultConfiguration
let isSuccess = try Realm.deleteFiles(for: config)
if isSuccess == true {
print("local files were located and deleted")
} else {
print("no local files were deleted, files were not found")
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
I think, you can check this link.
https://forum.realm.io/t/is-it-possible-to-reset-the-default-realm-without-creating-a-new-instance/1466
This one solve my realm database issue and can reset all schemas
I hope it works well!
I need to import 3D model from server URL but it's not working properly.
Here is my code:
guard let path = modelPath, !path.isEmpty else {
fatalError("Failed to find model file path.")
}
guard let modelURL = URL(string: path) else {
fatalError("Failed to find model URL.")
}
let asset = MDLAsset(url:modelURL)
guard let object = asset.object(at: 0) as? MDLMesh else {
fatalError("Failed to get mesh from asset.")
}
...crash here at object.
MDLAsset(url:) does not handle downloading models from a server, it's only for URLs that point to local storage.
You will have to download it yourself (using URLSession or a framework like Alamofire).
Example using URLSession:
Download task will return temporary location for the file that will be deleted after the callback closure return so if you need to reuse the file you will have to re-save it somewhere.
The tempLocation file will have an extension of .tmp, which MDLAsset will not be able to process. Even if you don't need to persist the file, I didn't come up with a better way than to re-save it with the needed extension (.obj that is).
let fileManager = FileManager.default
let localModelName = "model.obj"
let serverModelURL = URL(...)
let localModelURL = fileManager
.urls(for: .documentDirectory, in: .userDomainMask[0]
.appendingPathComponent(localModelName)
let session = URLSession(configuration: .default)
let task = session.downloadTask(with: modelURL) { tempLocation, response, error in
guard let tempLocation = tempLocation else {
// handle error
return
}
do {
// FileManager's copyItem throws an error if the file exist
// so we check and remove previously downloaded file
// That's just for testing purposes, you probably wouldn't want to download
// the same model multiple times instead of just persisting it
if fileManager.fileExists(atPath: localModelURL.path) {
try fileManager.removeItem(at: localModelURL)
}
try fileManager.copyItem(at: tempLocation, to: localModelURL)
} catch {
// handle error
}
let asset = MDLAsset(url: localURL)
guard let object = asset.object(at: 0) as? MDLMesh else {
fatalError("Failed to get mesh from asset.")
}
}
task.resume() // don't forget to call resume to start downloading
I think that .obj objects also need at least an .mlt file and probably an .jpg file for texture, check if you have an error because these files missing
I'm using FMDatabase library to used prepped database sqlite.
I got this error:
Error Domain=FMDatabase Code=8 "attempt to write a readonly database" UserInfo={NSLocalizedDescription=attempt to write a readonly database}
2017-10-27 19:59:10.983238+0330 kashanmap[417:63718] Unknown error calling sqlite3_step (8: attempt to write a readonly database) eu
2017-10-27 19:59:10.983473+0330 kashanmap[417:63718] DB Query: insert into LocationInfoFa
it's my class:
import FMDB
class DatabaseManager {
private let dbFileName = "kashanmapDB_upgrade_3-4.db"
private var database:FMDatabase!
let TABLE_LOCATION_FA = "LocationInfoFa";
let TABLE_LOCATION_EN = "LocationInfoEn";
let TABLE_GREAT_PEOPLE_FA = "GreatPeopleInfoFa";
let TABLE_GREAT_PEOPLE_EN = "GreatPeopleInfoEn";
let TABLE_TAGS = "Tags";
let TABLE_RELATION_TAG_LOCATION = "RelationTagLocation";
let TABLE_NECESSARY_INFORMATION = "NecessaryInformation";
let TABLE_SLIDER_FA = "SliderFa";
let TABLE_SLIDER_EN = "SliderEn";
let DATABASE_VERSION = 4;
static var LANGUAGE = 1 ; //1:Fa , 2:En
var utilities = Utilities()
init() {
openDatabase()
if(utilities.getData(key: "lang") == "2")
{
DatabaseManager.LANGUAGE = 2
}
}
func openDatabase() {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let dbPath = URL(fileURLWithPath: paths).appendingPathComponent(dbFileName)
let str_path = Bundle.main.resourceURL!.appendingPathComponent(dbFileName).path
let database = FMDatabase(path: str_path)
/* Open database read-only. */
if (!(database.open(withFlags: 2))) {
print("Could not open database at \(dbPath).")
} else {
print("opened database")
self.database = database;
}
}
func closeDatabase() {
if (database != nil) {
database.close()
}
}
path of my database:
my query:
do {
let db = database
let q = try db?.executeUpdate("insert into \(table) (catid,subcat_id,id,subcat_title,title,description,lat,lon,takhfif,images,wifi,apple_health,wc,full_time,pos,work_hours,phone,mobile,fax,website,email,address,facebook,instagram,linkedin,telegram,googleplus,twitter,publish,feature,manager,city,rating_sum,rate_count,lastip,parking,isMallID,mallID,discount_images,price_images,newProduct_images,services_images,order_online,out_upon,cat_title,cat_icon,last_modify,item_logo,cat_logo,rate_sum1,rate_sum2,rate_sum3,rate_count1,rate_count2,rate_count3,rate_title1,rate_title2,rate_title3,rate_enable,installments_text,installments_image) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", values:[ catid,subcat_id,id,subcat_title,title,description,lat,lon,takhfif,images,wifi,apple_health,wc,full_time,pos,work_hours,phone,mobile,fax,website,email,address,facebook,instagram,linkedin,telegram,googleplus,twitter,publish,feature,manager,city,rating_sum,rate_count,lastip,parking,isMallID,mallID,discount_images,price_images,newProduct_images,services_images,order_online,out_upon,cat_title,cat_icon,last_modify,item_logo,cat_logo,rate_sum1,rate_sum2,rate_sum3,rate_count1,rate_count2,rate_count3,rate_title1,rate_title2,rate_title3,rate_enable,installments_text,installments_image])
} catch {
print("\(error)")
}
there are some solutions in stack overflow but them don't accepted as true answer.
updated2
I got this error:
DB does not exist in documents folder
my code:
init() {
openDatabase()
if(utilities.getData(key: "lang") == "2")
{
DatabaseManager.LANGUAGE = 2
}
}
func copyDatabaseIfNeeded() {
// Move database file from bundle to documents folder
let fileManager = FileManager.default
let documentsUrl = fileManager.urls(for: .documentDirectory,
in: .userDomainMask)
guard documentsUrl.count != 0 else {
return // Could not find documents URL
}
let finalDatabaseURL = documentsUrl.first!.appendingPathComponent("kashanmapDB_upgrade_3-4.db")
if !( (try? finalDatabaseURL.checkResourceIsReachable()) ?? false) {
print("DB does not exist in documents folder")
let documentsURL = Bundle.main.resourceURL?.appendingPathComponent("kashanmapDB_upgrade_3-4.db")
do {
try fileManager.copyItem(atPath: (documentsURL?.path)!, toPath: finalDatabaseURL.path)
} catch let error as NSError {
print("Couldn't copy file to final location! Error:\(error.description)")
}
} else {
print("Database file found at path: \(finalDatabaseURL.path)")
}
}
func openDatabase() {
self.copyDatabaseIfNeeded()
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let dbPath = URL(fileURLWithPath: paths).appendingPathComponent(dbFileName)
let str_path = Bundle.main.resourceURL!.appendingPathComponent(dbFileName).path
let database = FMDatabase(path: str_path)
/* Open database read-only. */
if (!(database.open(withFlags: 2))) {
print("Could not open database at \(dbPath).")
} else {
print("opened database")
self.database = database;
}
}
You are facing this error because you are trying to write (update) the .db file in the bundle directory which is not allowed:
AppName.app:
This is the app’s bundle. This directory contains the app and all of
its resources. You cannot write to this directory. To prevent
tampering, the bundle directory is signed at installation time.
Writing to this directory changes the signature and prevents your app
from launching. You can, however, gain read-only access to any
resources stored in the apps bundle.
File System Basics - Table 1-1: Commonly used directories of an iOS app
If you are aiming to update the file, you should implement a logic to copy it -if it's not already has been copied before- into the documents directory, thus you'd be able to read/write transactions with the copied file.
Remark that for iOS 11 and above, you might want to copy the database file into the Application Support directory if you don't want to let be viewable to the end users when navigating to your app by the Files iOS app. For details, check the iOS Storage Best Practices Apple video session.
You'd notice that this logic should be applied to any file in the app main bundle, for instance it is also applicable for JSON files.