DatabaseReference.observe is not called in swift4 - ios

I am trying to fetch the data from firebase. I am calling a function which has a databaseReference but it is not calling up.Basically this function is also called from databaseRefernce only of another function.
Here is my code:
func prepareCoursesFromCourseNodewithAllCoursesList(allCourseList: [Any]){
var courseDetailsNode = String()
var courseCount = allCourseList.count
weak var weakSelf = self
var courseId = String()
var localCoursesAndCardDictionary = [AnyHashable: Any]()
for singleCourse in allCourseList as! [[String:Any]] {
if singleCourse["elementId"] != nil {
courseId = "\(String(describing: singleCourse["elementId"]!))"
}else{
if singleCourse["currentCourseId"] != nil {
courseId = "\(String(describing: singleCourse["currentCourseId"]!))"
}
}
if singleCourse["parentNodeName"] != nil {
if singleCourse["parentNodeName"] as! String == "course" {
//this is course
courseDetailsNode = IMERCOURSE_URL
}
else {
//this is course Collection
courseDetailsNode = IMERCOURSECOLLECTION_URL
}
}
var reference = DatabaseReference()
let courseURL = "\(FIREBASE_URL)\(courseDetailsNode.replacingOccurrences(of: "{Id}", with: courseId))"
reference = Database.database().reference(fromURL: courseURL)
self.addIntoListFirebaseRef(firebaseRef: ref)
reference.observe(DataEventType.value, with: { (snapShot:DataSnapshot) in
courseCount -= 1
if snapShot.value != nil {
let singleCourseDictionary = snapShot.value as? [String: Any]
localCoursesAndCardDictionary[courseId] = singleCourseDictionary
self.settingUserDetailsViewData()
(Constants.sharedTools() as AnyObject).hideProgressIndicator()
}
}
}, withCancel: { (error:Error) in
})
}
}
}
this prepareCoursesFromCourseNodewithAllCoursesList(allCourseList: [Any]) is called from another databaseRefernce.ObserveEevnt
value.

Related

I have 2 view controllers with same logic but one of them is not working

I have 2 view models TransferViewModel which has the respective TransferViewController for making Local Transactions from a model LocalTransactionRequest and i have BankTransferViewModel which has a model BankTransactionsRequest, the first one is working but the second one is not, both view controllers are supposed to perform segue to another view controller ConfirmViewController, but the second one (BankTransferViewController) is not working
[This one is TransferViewController][1]
private func setupViewModel() {
viewModel.isTransfer = isTransfer
viewModel.loan = loan
viewModel.getBalance()
transferButton.rx.tap.asObservable().subscribe(onNext: { [weak self] _ in
guard let strongSelf = self else { return }
if let isVerified = UserManager.shared.get()?.IsVerified.value, isVerified{
strongSelf.viewModel.phoneNumberText.accept(strongSelf.phoneNumberTextField.text ?? "")
strongSelf.viewModel.amountText.accept(strongSelf.amountTextField.text ?? "")
strongSelf.viewModel.transfer()
}else{
strongSelf.showVerificationAlert()
}
}).disposed(by: disposeBag)
viewModel.accountInfo.asObservable().subscribe(onNext: { [weak self] accountInfo in
if let account = accountInfo{
guard let strongSelf = self else { return }
strongSelf.accountInfo = account
let request = LocalTransactionRequest(Identification: UserManager.shared.identification ?? "", Amount: Double(strongSelf.amountTextField.text!)!, ReceiverPhoneNumber: strongSelf.phoneNumberTextField.text!, IDBankAccount: UserManager.shared.defaultBankAccountId ?? -1, IsFromTransfer: strongSelf.isTransfer, Description: strongSelf.descriptionTF.text!)
strongSelf.transferRequest.accept(request)
strongSelf.performSegue(withIdentifier: "segue_toConfirmTransfer", sender: account)
}
}).disposed(by: disposeBag)
}
[This one is BankTransferViewController][2]
private func setupViewModel(){
viewModel.isTransfer = isTransfer
viewModel.getBalance()
transferButton.rx.tap.asObservable().subscribe(onNext: { [weak self] _ in
guard let strongSelf = self else { return }
if let isVerified = UserManager.shared.get()?.IsVerified.value, isVerified{
strongSelf.viewModel.bankNumberText.accept(strongSelf.bankNumberTextField.text ?? "")
strongSelf.viewModel.firstName.accept(strongSelf.firstNameTextField.text ?? "")
strongSelf.viewModel.lastName.accept(strongSelf.lastNameTextField.text ?? "")
strongSelf.viewModel.amountText.accept(strongSelf.amountTextField.text ?? "")
strongSelf.viewModel.descriptionText.accept(strongSelf.descriptionTF.text ?? "")
strongSelf.viewModel.transferNational()
}else{
strongSelf.showVerificationAlert()
}
}).disposed(by: disposeBag)
viewModel.transferRequest.asObservable().subscribe(onNext: { [weak self] bankRequest in
if let bank = bankRequest{
guard let strongSelf = self else { return }
strongSelf.bankTransferRequest = bank
let request = BankTransactionRequest(Identification: UserManager.shared.identification ?? "", ReceiverBankAccount: strongSelf.bankNumberTextField.text!, ReceiverFirst: strongSelf.firstNameTextField.text!, ReceiverLast: strongSelf.lastNameTextField.text!, Amount: Double(strongSelf.amountTextField.text!)!, Description: strongSelf.descriptionTF.text!)
strongSelf.nationalTransferRequest.accept(request)
DispatchQueue.main.async {
strongSelf.performSegue(withIdentifier: "segue_toConfirmTransfer", sender: bank)
}
}
}).disposed(by: disposeBag)
}
This is view model of BankTransferViewController
import RxCocoa
import RxSwift
class BankTransferViewModel: BaseViewModel {
private let transferUseCase: TransferUseCase
var accountInfo: BehaviorRelay<AccountExistModel?> = BehaviorRelay(value: nil)
var balance: BehaviorRelay<BalanceModel?> = BehaviorRelay(value: nil)
var bankNumberText: BehaviorRelay<String> = BehaviorRelay(value: "")
var firstName: BehaviorRelay<String> = BehaviorRelay(value: "")
var lastName: BehaviorRelay<String> = BehaviorRelay(value: "")
var amountText: BehaviorRelay<String> = BehaviorRelay(value: "")
var descriptionText: BehaviorRelay<String> = BehaviorRelay(value: "")
var transferRequest: BehaviorRelay<BankTransactionRequest?> = BehaviorRelay(value: nil)
var accountExist = PublishSubject<Bool>()
var hasMoney = PublishSubject<Bool>()
var invalidBankNumber = PublishSubject<Bool>()
var accountCannotRecieve = PublishSubject<Bool>()
var isTransfer : Bool = true
var transferPressed: AnyObserver<Void> {
return AnyObserver { [weak self] event in
switch event {
case .next:
guard let strongSelf = self else {
return
}
strongSelf.checkValidation()
default:
break
}
}
}
init(transferUseCase: TransferUseCase) {
self.transferUseCase = transferUseCase
}
func transferNational() {
self.checkValidation()
}
private func checkValidation() {
guard let balance = self.balance.value else {
state.onNext(.error(error: RepoError(with: "Dështoi verifikimi i disponueshmërisë financiare. Ju lusim të provoni më vonë.")))
return
}
if bankNumberText.value == ""{
state.onNext(.error(error: RepoError(with: "Plotëso fushën për numrin e bankës të pranuesit.")))
return
}
if bankNumberText.value.count < 6{
state.onNext(.error(error: RepoError(with:"Ju lutemi, shtypni një numër valid të gjirollogarisë")))
return
}
guard let doubleAmount = Double(amountText.value), doubleAmount > 0 else {
state.onNext(.error(error: RepoError(with: "Shuma jo e rregullt")))
return
}
if amountText.value == ""{
state.onNext(.error(error: RepoError(with: "Shuma jo e
saktë.")))
return
}
if balance.Balance < doubleAmount{
state.onNext(.error(error: RepoError(with: "Nuk keni fonde të mjaftueshme për realizimin e transaksionit.")))
return
}
if bankNumberText.value != "" && amountText.value != "" && (balance.Balance >= doubleAmount) {
// checkAccountExist()
}
}
func checkModulus16(accountNumber: String) -> Bool {
if accountNumber.isEmpty{
return false
}
let newValue = accountNumber.dropLast(2)
let mod = Int64(newValue + "00")! % 97
let result = 98 - mod
let derivedData = newValue + "" + (result < 10 ? "0\(result)" : "\(result)")
return Int64(derivedData) == Int64(accountNumber)
}
func showError(with message: String ) {
state.onNext(.error(error: RepoError(with: message)))
}
func getBalance(){
let params = ["Identification": UserManager.shared.identification ?? "" ] as ApiJson
transferUseCase.getBalance(with: params) {[weak self] (balance, error) in
guard let strongSelf = self else { return }
if let error = error {
strongSelf.state.onNext(.error(error: error))
strongSelf.accountExist.onNext(false)
}else if let balance = balance{
UserManager.shared.userBonus = balance.BonusAmount
strongSelf.state.onNext(.content)
strongSelf.balance.accept(balance)
strongSelf.accountExist.onNext(true)
UserManager.shared.updateBalance(with: balance)
}
}
}
//MARK: - baseViewModel
override func tryAgain() {
self.getBalance()
}
}
Make sure the following points are valid for your performSegue to work in BankTransferViewController:
The BankTransferViewController has a segue pointing to ConfirmViewController.
The identifier in your performSegue(withIdentifier: yourIdentifier, sender: yourModel) is the exact same identifier as the segue in storyboard that is connecting the two view controllers.
Since you are using it inside the viewModel.transferRequest.asObservable().subscribe(onNext: code, make sure you are emmiting a value to viewModel.transferRequest somewhere in the code. Otherwise, performSegue will never get called.
Since you have this check if let bank = bankRequest{ before using performSegue, make sure the transferRequest value you emmit is not nil.

getting 0 values inside my array from getdocument which insdie getdocuments

iam working with firestore i have two structs
one called history
aother called cart
simply hisory struct is
struct UserOrderHistoryModel {
var id : String? = ""
var dateOrderCreated : String? = ""
var cartArray : [CartItemModel]
}
struct CartItemModel {
var id : String? = ""
var restaurantImageUrl : String
var restaurantTitle : String
var menuItemImageUrl : String
var menuItemTitle : String
var countOfMenuItemSelected : Int
}
what i am trying to do is load history so i use getdocument to get the id and the date
i wanted to get order collection which inside history document
so i use another getdocuments inside the first one
func loadUserOrderHistory(completion : #escaping (_ error :Error? ,_ userHistoryArray : [UserOrderHistoryModel]?) -> ()) {
var historyArray = [UserOrderHistoryModel]()
let userHistoryRef = USERS.document(UserConfigurations.currentUserID!).collection("history")
userHistoryRef.getDocuments { (snapShots, error) in
if error != nil {
completion(error , nil)
}else {
historyArray.removeAll()
for document in snapShots!.documents {
let historyId = document.documentID
let historyData = document.data()
let historyDate = historyData["date_order_created"] as? Timestamp ?? nil
let historyDateToString = String(describing: historyDate?.dateValue())
var orderArray = [CartItemModel]()
self.loadUserHistoryOrders(histroyDocumentReference: userHistoryRef.document(historyId), completion: { (error, cartArray) in
if error != nil {
print(error!)
}else {
orderArray = cartArray!
}
})
let userHistory = UserOrderHistoryModel(id: historyId, dateOrderCreated: historyDateToString , cartArray: self.orderArray)
historyArray.append(userHistory)
}
completion(nil , historyArray)
}
}
}
private func loadUserHistoryOrders( histroyDocumentReference : DocumentReference, completion : #escaping (_ error : Error? ,_ historyOrders : [CartItemModel]? ) -> ()) {
var cartArray = [CartItemModel]()
histroyDocumentReference.collection("orders").getDocuments { (snapShot, error) in
if error != nil {
completion(error,nil)
}else {
for document in snapShot!.documents {
let id = document.documentID
let cartDictionary = document.data()
let restaurantImageUrl = cartDictionary["restaurant_imageurl"] as? String ?? "none"
let restaurantName = cartDictionary["restaurant_title"] as? String ?? "none"
let menuItemImageUrl = cartDictionary["menuItem_imageurl"] as? String ?? "none"
let menuItemName = cartDictionary["menuItem_title"] as? String ?? "none"
let count = cartDictionary["number_of_selected_menuitem"] as? Int ?? 0
let cart = CartItemModel(id: id, restaurantImageUrl: restaurantImageUrl, restaurantTitle: restaurantName, menuItemImageUrl: menuItemImageUrl, menuItemTitle: menuItemName, countOfMenuItemSelected: count)
cartArray.append(cart)
}
completion(nil , cartArray)
}
}
}
so orderArray inside second getdocumnet which i put it inside another function called loadUserHistoryOrders
i debugged the code and found that
once i get to end of the this function orderArray is back to 0 values
here is the pics of my firestore
url of pics : https://drive.google.com/open?id=1NX8NIUN2Yb9m3_7A8EnZgAxWe8xuhNDh
Update :
i solved the problem by adding completion of loadUserOrderHistory inside the call of the second method loadUserHistoryOrders
func loadUserOrderHistory(completion : #escaping (_ error :Error? ,_ userHistoryArray : [UserOrderHistoryModel]?) -> ()) {
var historyArray = [UserOrderHistoryModel]()
let userHistoryRef = USERS.document(UserConfigurations.currentUserID!).collection("history")
userHistoryRef.getDocuments { (snapShots, error) in
if error != nil {
completion(error , nil)
}else {
historyArray.removeAll()
for document in snapShots!.documents {
let historyId = document.documentID
let historyData = document.data()
let historyDate = historyData["date_order_created"] as? Timestamp ?? nil
let historyDateToString = String(describing: historyDate?.dateValue())
var orderArray = [CartItemModel]()
self.loadUserHistoryOrders(histroyDocumentReference: userHistoryRef.document(historyId), completion: { (error, cartArray) in
if error != nil {
print(error!)
}else {
orderArray = cartArray!
let userHistory = UserOrderHistoryModel(id: historyId, dateOrderCreated: historyDateToString , cartArray: self.orderArray)
historyArray.append(userHistory)
completion(nil , historyArray)
}
})
}
}
}
}

addAnnotations method only places last annotation from Array

I have problem adding annotations to mapView. I had success with this code:
func placeAnnotations() {
for _ in placeDetails {
let multipleAnnotations = MKPointAnnotation()
multipleAnnotations.title = place.address
multipleAnnotations.subtitle = place.phone
multipleAnnotations.coordinate = CLLocationCoordinate2D(latitude: place.lat, longitude: place.lng)
mapView.addAnnotation(multipleAnnotations)
}
}
Problem is, it is not conforming to my Place class, thus not showing custom Title, Subtitle and MKAnnotationView. This is code inside viewDidLoad(), where I'm trying to put all the annotations, but it keeps adding only last one. I understood that it overrides all the previous ones from array, but haven't found any other way/method to implement.
var placeDetails = [Place]()
var places = [Place]()
override func viewDidLoad() {
super.viewDidLoad()
downloadPlaceID {
for obj in places {
place.downloadDetails(input: obj.placeId, completed: {
self.placeDetails.append(obj)
//self.placeAnnotations()
self.mapView.addAnnotations(self.placeDetails)
})
}
}
}
And this is my class with all the data conforming to MKAnnotation
protocol, and functions, downloadPlaceID() and downloadDetails()
class Place: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var placeId: String!
var vicinity: String!
var phone: String!
var workHours: Bool!
var lat: Double!
var lng: Double!
var address: String!
var subtitle: String? {
return phone
}
var title: String? {
return address
}
var _placeId: String {
if placeId == nil {
placeId = ""
}
return placeId
}
var _vicinity: String {
if vicinity == nil {
vicinity = ""
}
return vicinity
}
var _phone: String {
if phone == nil {
phone = ""
}
return phone
}
var _workHours: Bool {
if workHours == nil {
workHours = false
}
return workHours
}
var _lat: Double {
if lat == nil {
lat = 0.0
}
return lat
}
var _lng: Double {
if lng == nil {
lng = 0.0
}
return lng
}
var _address: String {
if address == nil {
address = ""
}
return address
}
init(place: [String:Any]) {
if let ids = place["place_id"] as? String {
self.placeId = ids
}
if let vicinities = place["vicinity"] as? String {
self.vicinity = vicinities
}
self.coordinate = CLLocationCoordinate2DMake(0.0, 0.0)
}
func downloadDetails(input: String, completed: #escaping DownloadComplete) {
let details = "\(detailsBaseURL)\(detailsPlaceId)\(input)\(detailsKey)\(detailsSearchAPIKey)"
Alamofire.request(details).responseJSON { response in
let result = response.result
if let dictionary = result.value as? [String:Any] {
if let result = dictionary["result"] as? [String:Any] {
if let phoneNumber = result["formatted_phone_number"] as? String {
self.phone = phoneNumber
}
if let geometry = result["geometry"] as? [String:Any] {
if let location = geometry["location"] as? [String:Any] {
if let latitude = location["lat"] as? Double {
self.lat = latitude
}
if let longitude = location["lng"] as? Double {
self.lng = longitude
}
self.coordinate = CLLocationCoordinate2DMake(self.lat, self.lng)
}
}
if let openingHours = result["opening_hours"] as? [String:Any] {
if let openNow = openingHours["open_now"] as? Bool {
self.workHours = openNow
}
}
if let addressComponents = result["address_components"] as? [[String:Any]] {
let longName = addressComponents[1]["long_name"] as? String
let shortName = addressComponents[0]["long_name"] as? String
self.address = "\(longName!),\(shortName!)"
}
}
}
completed()
}
}
}
func downloadPlaceID (completed: #escaping DownloadComplete) {
let placeURL = URL(string: nearbyURL)
Alamofire.request(placeURL!).responseJSON { (response) in
let result = response.result
if let dictionary = result.value as? [String:Any] {
if let results = dictionary["results"] as? [[String:Any]] {
if let status = dictionary["status"] as? String {
if status == "OK" {
for obj in results {
place = Place(place: obj)
places.append(place)
}
} else {
print("jede govna")
}
}
}
}
completed()
}
There's some odd mixing of variable names and concepts here that makes your code somewhat hard to understand.
As an example, assigning a variable you call vicinities, plural, to an attribute called vicinity, singular. Or not separating your downloadDetails function from your data model.
That aside, it looks to me like you're unnecessarily adding your MKAnnotations many times to your map, by adding your array of [MKAnnotation] to your map in each loop.
I suspect you've done this because you've made it hard for yourself to know when the whole array is done updating its details.
As a quick fix, I'd suggest changing your downloadDetails function to call the completed function with the place you've just downloaded details for. Here's a really simplified, but working, version of what you are trying to do. First your Place class:
class Place: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
override init() {
coordinate = CLLocationCoordinate2DMake(0, 0)
}
func downloadDetails(completed: #escaping (Place) -> Void) {
// Instead of downloading details we are just creating random positions
self.coordinate = CLLocationCoordinate2DMake(CLLocationDegrees(arc4random_uniform(50)), CLLocationDegrees(arc4random_uniform(50)))
// Return the object you've just built
completed(self)
}
}
Now in your view controller, here I am starting with an array of 50 Place objects, getting the details for them and placing them on the map:
var places = [Place]()
for _ in 1...50 {
places.append(Place())
}
for place in places {
place.downloadDetails(completed: { (placeWithDetails) in
self.mapView.addAnnotation(placeWithDetails)
})
}
This results in the map being populated with 50 random places:

How to save and fetch data from file in swift?

I want to save the response from JSON in a file and fetch from it when the network is not available. However on trying to fetch idea by disabling the wifi, the app always crashes. Are there any other ways for offline fetching in swift except saving in database??
This is the error I am getting : Could not cast value of type 'Swift._NSContiguousString' (0x109e22320) to 'NSArray'
This is what I have done so far:
Create a model
class Directory : NSObject, NSCoding {
var data : [AnyObject]
var tid : String
var vid : String
var name : String
var imgThumbnail : String
var imgMedium : String
var imgLarge : String
var child : String
// MARK: Archiving Paths
init(data:[AnyObject],tid:String,vid:String,name:String,imgThumbnail:String,imgMedium:String,imgLarge:String,child:String) {
self.data = data ?? []
self.tid = tid ?? ""
self.vid = vid ?? ""
self.name = name ?? ""
self.imgThumbnail = imgThumbnail ?? ""
self.imgMedium = imgMedium ?? ""
self.imgLarge = imgLarge ?? ""
self.child = child ?? ""
}
// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(data, forKey:Constants.kData)
aCoder.encodeObject(name, forKey:Constants.Directory.kName )
aCoder.encodeObject(tid, forKey: Constants.Directory.tid)
aCoder.encodeObject(vid, forKey: Constants.Directory.vid)
aCoder.encodeObject(imgThumbnail, forKey:Constants.Directory.kImageThumbnail)
aCoder.encodeObject(imgMedium, forKey: Constants.Directory.kImageMedium)
aCoder.encodeObject(imgLarge, forKey: Constants.Directory.kImageLarge)
aCoder.encodeObject(child, forKey: Constants.Directory.kChild)
}
required convenience init?(coder aDecoder: NSCoder) {
let data = aDecoder.decodeObjectForKey(Constants.kData) as! [AnyObject]
let name = aDecoder.decodeObjectForKey(Constants.Directory.kName) as! String
let tid = aDecoder.decodeObjectForKey(Constants.Directory.tid) as! String
let vid = aDecoder.decodeObjectForKey(Constants.Directory.vid) as! String
let imgThumbnail = aDecoder.decodeObjectForKey(Constants.Directory.kImageThumbnail) as! String
let imgMedium = aDecoder.decodeObjectForKey(Constants.Directory.kImageMedium) as! String
let imgLarge = aDecoder.decodeObjectForKey(Constants.Directory.kImageLarge) as! String
let child = aDecoder.decodeObjectForKey(Constants.Directory.kChild) as! String
// Must call designated initializer.
self.init(data:data,tid:tid,vid:vid,name:name,imgThumbnail:imgThumbnail,imgMedium: imgMedium,imgLarge: imgLarge, child: child)
}
}
Code for saving and loading the data from file
class func loadSavedFile(fileName: String) -> AnyObject? {
let pathString: String = Utility.fetchFilePathString(fileName)
print("Here the pathString is \(pathString)")
if NSFileManager.defaultManager().fileExistsAtPath(pathString) {
return NSKeyedUnarchiver.unarchiveObjectWithFile(pathString)!
} else {
return "File doesn't exist"
}
return ""
}
class func saveObject(object: AnyObject, toFile fileName: String) {
let pathString: String = Utility.fetchFilePathString(fileName)
NSKeyedArchiver.archiveRootObject(object, toFile: pathString)
}
class func fetchFilePathString(fileName: String) -> String {
let pathAray: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.AllDomainsMask, true)
let pathString = pathAray.last!
return NSURL(fileURLWithPath: pathString as! String).URLByAppendingPathComponent(fileName).absoluteString
}
Checking for network connection in the view controller
var directoryArr = [Directory]()
override func viewDidLoad() {
super.viewDidLoad()
if Utility.isNetworkReachable() {
Utility.saveObject([], toFile: Constants.File.kDirectory)
self.serviceCallDirectory()
} else {
self.directorie = (Utility.loadSavedFile(Constants.File.kDirectory) as? [Directory])!
self.tableView.reloadData()
}
Service Call
func serviceCallDirectory() -> Void {
let stringUrl = Constants.baseUrl + Constants.kDirectoryUrl
WebService.getRequestAPI(stringUrl, withSuccess: {(responseDic, Statusflag,error) in
if Statusflag {
self.tableView.backgroundColor = UIColor.clearColor()
self.tableView.hidden = false
let tempInfo = responseDic![Constants.kData] as! [AnyObject]
var imgthumbnail : String = ""
var imgmedium : String = ""
var imglarge : String = ""
var name : String = ""
var child : String = ""
if tempInfo.count != 0 {
for info in tempInfo {
let tid = info[Constants.Directory.tid] as! String
let vid = info[Constants.Directory.vid] as! String
if let names = info[Constants.Directory.kName] as? String {
name = names
}
if let childs = info[Constants.Directory.kChild] as? String {
child = childs
}
if let imgthumb = info[Constants.Directory.kImageThumbnail] as? String {
imgthumbnail = imgthumb
} else {
imgthumbnail = ""
}
if let imgmediumd = info[Constants.Directory.kImageMedium] as? String {
imgmedium = imgmediumd
} else {
imgmedium = ""
}
if let imglarges = info[Constants.Directory.kImageLarge] as? String {
imglarge = imglarges
}
let myModel = Directory(
data: tempInfo,
tid: tid,
vid: vid,
name: name,
imgThumbnail: imgthumbnail,
imgMedium: imgmedium,
imgLarge: "",
child: child
)
self.directorie.append(myModel)
}
I don't know that this is the only issue, but this code
class func loadSavedFile(fileName: String) -> AnyObject? {
let pathString: String = Utility.fetchFilePathString(fileName)
print("Here the pathString is \(pathString)")
if NSFileManager.defaultManager().fileExistsAtPath(pathString) {
return NSKeyedUnarchiver.unarchiveObjectWithFile(pathString)!
} else {
return "File doesn't exist"
}
return ""
}
Either returns an object or a string. That's not very sensible. It should return a success flag or a tuple or use a completion block. When you call this function your code expects to get back an array of directory, which in a number of cases won't happen
self.directorie = (Utility.loadSavedFile(Constants.File.kDirectory) as? [Directory])!
The error in your question indicates a different kind of data mismatch. You should try not to use AnyObject, let swift help you by type checking what you're doing...

Can I serialize a RealmObject to JSON or to NSDictionary in Realm for Swift?

I'm testing Realm, but I cant find a easy way to convert my object to JSON.
I need to push the data to my REST interface.
How can I do it using swift?
class Dog: Object {
dynamic var name = ""
}
class Person : Object {
dynamic var name = ""
let dogs = List<Dog>()
}
I'm trying something like this, but I can't iterate unknown objects (List)
extension Object {
func toDictionary() -> NSDictionary {
let props = self.objectSchema.properties.map { $0.name }
var dicProps = self.dictionaryWithValuesForKeys(props)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dicProps)
for prop in self.objectSchema.properties as [Property]! {
if let objectClassName = prop.objectClassName {
if let x = self[prop.name] as? Object {
mutabledic.setValue(x.toDictionary(), forKey: prop.name)
} else {
//problem here!
}
}
}
return mutabledic
}
}
**sorry for ugly code.
I am also new to Realm but I think the easiest way is to reflect on Object's schema:
class Person: Object {
dynamic var name = ""
dynamic var age = 0
}
let person = Person()
let schema = person.objectSchema
let properties = schema.properties.map() { $0.name }
let dictionary = person.dictionaryWithValuesForKeys(properties) // NSDictionary
println(properties)
println(dictionary)
I think that I found the solution.
I'm not reliant about performance.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dicProps = self.dictionaryWithValuesForKeys(properties)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dicProps)
for prop in self.objectSchema.properties as [Property]! {
if let objectClassName = prop.objectClassName {
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
if let object = nestedListObject._rlmArray[index] as? Object {
objects.append(object.toDictionary())
}
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
}
return mutabledic
}
}
Here is my solution. use unsafeBitCast to avoid cast fail warning.
extension Object {
func toDictionary() -> [String:AnyObject] {
let properties = self.objectSchema.properties.map { $0.name }
var dicProps = [String:AnyObject]()
for (key, value) in self.dictionaryWithValuesForKeys(properties) {
if let value = value as? ListBase {
dicProps[key] = value.toArray()
} else if let value = value as? Object {
dicProps[key] = value.toDictionary()
} else {
dicProps[key] = value
}
}
return dicProps
}
}
extension ListBase {
func toArray() -> [AnyObject] {
var _toArray = [AnyObject]()
for i in 0..<self._rlmArray.count {
let obj = unsafeBitCast(self._rlmArray[i], Object.self)
_toArray.append(obj.toDictionary())
}
return _toArray
}
}

Resources