将本地领域转换为同步领域:'customSchema' 无法访问
Converting local Realms to synced Realms: 'customSchema' is inaccessible
我阅读了有关 Objective-C 的 Converting Local Realms to Synced Realms section in docs and I found this nice recipe,但我无法在 Swift 中完全实现的应用程序上实现它。
var syncConfig = Realm.Configuration()
syncConfig.syncConfiguration = SyncConfiguration(user: user, realmURL: server.appendingPathComponent("/~/app1"))
syncConfig.customSchema = localRealm.schema
~~~~~~~~~~~~~~~~~~~~~~~
^ 'customSchema' is inaccessible due to 'private' protection level
我什至添加了import Realm.Private
但没有解决问题
我应该为这个操作明确使用 Objective-C 吗?
没有 public customSchema
属性,您可以随时参考文档(找出供 public 使用的最佳方法):
https://realm.io/docs/objc/2.10.1/api/Classes/RLMRealmConfiguration.html
没有更好的选择,我决定在我的 Swift 项目中使用 Objective-C。所以,我添加了一个 SWIFT_OBJC_BRIDGING_HEADER
(当你添加一个 Objective-C 文件时,Xcode 会自动执行)并创建了一个 RealmConverter
对象:
RealmConverter.h
#import <Foundation/Foundation.h>
@import Realm;
NS_ASSUME_NONNULL_BEGIN
@interface RealmConverter : NSObject
- (void)convertLocalToSyncRealm:(NSURL *)server local:(NSURL *)local username:(NSString *)username password:(NSString *)password completion:(void (^)(NSError * _Nullable))completion;
@end
NS_ASSUME_NONNULL_END
RealmConverter.m
#import "RealmConverter.h"
@import Realm.Dynamic;
@import Realm.Private;
@implementation RealmConverter
- (void)convertLocalToSyncRealm:(NSURL *)server local:(NSURL *)local username:(NSString *)username password:(NSString *)password completion:(void (^)(NSError * _Nullable))completion {
RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init];
configuration.fileURL = local;
configuration.dynamic = true;
configuration.readOnly = YES;
RLMRealm *localRealm = [RLMRealm realmWithConfiguration:configuration error:nil];
RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithUsername:username password:password register:YES];
[RLMSyncUser logInWithCredentials:credentials authServerURL:server onCompletion:^(RLMSyncUser *syncUser, NSError *error) {
if (error) {
completion(error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
RLMRealmConfiguration *syncConfig = [[RLMRealmConfiguration alloc] init];
syncConfig.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:syncUser realmURL:[NSURL URLWithString:[NSString stringWithFormat:@"realm://%@:%@/~/<redacted>", server.host, server.port]]];
syncConfig.customSchema = [localRealm.schema copy];
RLMRealm *syncRealm = [RLMRealm realmWithConfiguration:syncConfig error:nil];
syncRealm.schema = syncConfig.customSchema;
NSError *error = nil;
[syncRealm transactionWithBlock:^{
NSArray *objectSchema = syncConfig.customSchema.objectSchema;
for (RLMObjectSchema *schema in objectSchema) {
RLMResults *allObjects = [localRealm allObjects:schema.className];
for (RLMObject *object in allObjects) {
RLMCreateObjectInRealmWithValue(syncRealm, schema.className, object, true);
}
}
completion(nil);
} error:&error];
if (error) {
completion(error);
}
});
}];
}
@end
然后将 #import "RealmConverter.h"
添加到您的桥接头,然后在您的 Swift 代码中使用它,例如:
RealmConverter().convertLocal(toSyncRealm: URL(string: "http://localhost:9080")!, local: Realm.Configuration.defaultConfiguration.fileURL!, username: "user@example.com", password: "12345678") { error in
print("Done:", error ?? "nil")
}
在这里找到 Swift 函数的端口:https://github.com/realm/realm-cocoa/issues/538
import Realm
import Realm.Dynamic
import RealmSwift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let sourceFilePath = Bundle.main.url(forResource: "fieldFlow", withExtension: "realm")
let configuration = RLMRealmConfiguration()
configuration.fileURL = sourceFilePath
configuration.dynamic = true
configuration.readOnly = true
let localRealm = try! RLMRealm(configuration: configuration)
let creds = SyncCredentials.usernamePassword(username: "admin@realm.io", password: "password")
SyncUser.logIn(with: creds, server: URL(string: "http://localhost:9080")!) { (syncUser, error) in
DispatchQueue.main.async {
if let syncUser = syncUser {
self.copyToSyncRealmWithRealm(realm: localRealm, user: syncUser)
}
}
}
}
func copyToSyncRealmWithRealm(realm: RLMRealm, user: RLMSyncUser) {
let syncConfig = RLMRealmConfiguration()
syncConfig.syncConfiguration = RLMSyncConfiguration(user: user, realmURL: URL(string: "realm://localhost:9080/~/fieldRow")!)
syncConfig.customSchema = realm.schema
let syncRealm = try! RLMRealm(configuration: syncConfig)
syncRealm.schema = syncConfig.customSchema!
try! syncRealm.transaction {
let objectSchema = syncConfig.customSchema!.objectSchema
for schema in objectSchema {
let allObjects = realm.allObjects(schema.className)
for i in 0..<allObjects.count {
let object = allObjects[i]
RLMCreateObjectInRealmWithValue(syncRealm, schema.className, object, true)
}
}
}
}
我阅读了有关 Objective-C 的 Converting Local Realms to Synced Realms section in docs and I found this nice recipe,但我无法在 Swift 中完全实现的应用程序上实现它。
var syncConfig = Realm.Configuration()
syncConfig.syncConfiguration = SyncConfiguration(user: user, realmURL: server.appendingPathComponent("/~/app1"))
syncConfig.customSchema = localRealm.schema
~~~~~~~~~~~~~~~~~~~~~~~
^ 'customSchema' is inaccessible due to 'private' protection level
我什至添加了import Realm.Private
但没有解决问题
我应该为这个操作明确使用 Objective-C 吗?
没有 public customSchema
属性,您可以随时参考文档(找出供 public 使用的最佳方法):
https://realm.io/docs/objc/2.10.1/api/Classes/RLMRealmConfiguration.html
没有更好的选择,我决定在我的 Swift 项目中使用 Objective-C。所以,我添加了一个 SWIFT_OBJC_BRIDGING_HEADER
(当你添加一个 Objective-C 文件时,Xcode 会自动执行)并创建了一个 RealmConverter
对象:
RealmConverter.h
#import <Foundation/Foundation.h>
@import Realm;
NS_ASSUME_NONNULL_BEGIN
@interface RealmConverter : NSObject
- (void)convertLocalToSyncRealm:(NSURL *)server local:(NSURL *)local username:(NSString *)username password:(NSString *)password completion:(void (^)(NSError * _Nullable))completion;
@end
NS_ASSUME_NONNULL_END
RealmConverter.m
#import "RealmConverter.h"
@import Realm.Dynamic;
@import Realm.Private;
@implementation RealmConverter
- (void)convertLocalToSyncRealm:(NSURL *)server local:(NSURL *)local username:(NSString *)username password:(NSString *)password completion:(void (^)(NSError * _Nullable))completion {
RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init];
configuration.fileURL = local;
configuration.dynamic = true;
configuration.readOnly = YES;
RLMRealm *localRealm = [RLMRealm realmWithConfiguration:configuration error:nil];
RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithUsername:username password:password register:YES];
[RLMSyncUser logInWithCredentials:credentials authServerURL:server onCompletion:^(RLMSyncUser *syncUser, NSError *error) {
if (error) {
completion(error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
RLMRealmConfiguration *syncConfig = [[RLMRealmConfiguration alloc] init];
syncConfig.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:syncUser realmURL:[NSURL URLWithString:[NSString stringWithFormat:@"realm://%@:%@/~/<redacted>", server.host, server.port]]];
syncConfig.customSchema = [localRealm.schema copy];
RLMRealm *syncRealm = [RLMRealm realmWithConfiguration:syncConfig error:nil];
syncRealm.schema = syncConfig.customSchema;
NSError *error = nil;
[syncRealm transactionWithBlock:^{
NSArray *objectSchema = syncConfig.customSchema.objectSchema;
for (RLMObjectSchema *schema in objectSchema) {
RLMResults *allObjects = [localRealm allObjects:schema.className];
for (RLMObject *object in allObjects) {
RLMCreateObjectInRealmWithValue(syncRealm, schema.className, object, true);
}
}
completion(nil);
} error:&error];
if (error) {
completion(error);
}
});
}];
}
@end
然后将 #import "RealmConverter.h"
添加到您的桥接头,然后在您的 Swift 代码中使用它,例如:
RealmConverter().convertLocal(toSyncRealm: URL(string: "http://localhost:9080")!, local: Realm.Configuration.defaultConfiguration.fileURL!, username: "user@example.com", password: "12345678") { error in
print("Done:", error ?? "nil")
}
在这里找到 Swift 函数的端口:https://github.com/realm/realm-cocoa/issues/538
import Realm
import Realm.Dynamic
import RealmSwift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let sourceFilePath = Bundle.main.url(forResource: "fieldFlow", withExtension: "realm")
let configuration = RLMRealmConfiguration()
configuration.fileURL = sourceFilePath
configuration.dynamic = true
configuration.readOnly = true
let localRealm = try! RLMRealm(configuration: configuration)
let creds = SyncCredentials.usernamePassword(username: "admin@realm.io", password: "password")
SyncUser.logIn(with: creds, server: URL(string: "http://localhost:9080")!) { (syncUser, error) in
DispatchQueue.main.async {
if let syncUser = syncUser {
self.copyToSyncRealmWithRealm(realm: localRealm, user: syncUser)
}
}
}
}
func copyToSyncRealmWithRealm(realm: RLMRealm, user: RLMSyncUser) {
let syncConfig = RLMRealmConfiguration()
syncConfig.syncConfiguration = RLMSyncConfiguration(user: user, realmURL: URL(string: "realm://localhost:9080/~/fieldRow")!)
syncConfig.customSchema = realm.schema
let syncRealm = try! RLMRealm(configuration: syncConfig)
syncRealm.schema = syncConfig.customSchema!
try! syncRealm.transaction {
let objectSchema = syncConfig.customSchema!.objectSchema
for schema in objectSchema {
let allObjects = realm.allObjects(schema.className)
for i in 0..<allObjects.count {
let object = allObjects[i]
RLMCreateObjectInRealmWithValue(syncRealm, schema.className, object, true)
}
}
}
}