I'm using UICollectionView to display various images. I'm storing the path of images in realm.I want to create an array of images and store it in realm with all images in one array.
My code:
My realm Object
class cityDetail: Object {
dynamic var id = UUID().uuidString
dynamic var cityName = ""
dynamic var descrp = ""
dynamic var state = ""
dynamic var season = ""
dynamic var longitude = ""
dynamic var latitude = ""
var imgList = List<cityImage>()
override static func primaryKey() -> String? {
return "id"
}}
class cityImage:Object {
dynamic var imgStr = ""}
My function:
#IBAction func setIMG(_ sender:UIButton) {
self.img.isHidden = true
self.imgArray.append(imgURL)
print(imgArray)
newImage.imgStr = imgURL
citydetails.imgList.append(newImage)
let realm = try! Realm()
try! realm.write {
realm.add(newImage)
}
self.collection.reloadData()
}
Function in which I want array of path of images:
#IBAction func sendData(_ sender:UIButton) {
let citydetails = cityDetail()
let newImage = cityImage()
citydetails.cityName = self.cityName.text!
citydetails.descrp = self.descrp.text!
citydetails.state = self.state.text!
citydetails.season = self.season.text!
citydetails.latitude = String(lon)
citydetails.longitude = String(lat)
citydetails.imgList = newImage
let realm = try! Realm()
do {
try realm.write() {
realm.add(citydetails)
}
} catch {
}
self.collection.reloadData()
self.img.isHidden = true
}
Related
I am storing workout information in Realm from this object class:
class Workout: Object {
#objc dynamic var date: Date?
#objc dynamic var name: String?
#objc dynamic var exercise: String?
#objc dynamic var sets = 0
#objc dynamic var reps = 0
#objc dynamic var kg: Double = 0.0
#objc dynamic var notes: String?
}
I have data stored as an array, that I want to write to Realm, like this:
var workoutName = ""
var exercises = [String]()
var sets = [Int]()
var reps = [Int]()
var kg = [Double]()
var notes = [String]()
#IBAction func saveWorkoutButton(_ sender: Any) {
let realm = try! Realm()
print(Realm.Configuration.defaultConfiguration.fileURL!)
let currenDate = Date() // Get the current date
let myWorkout = Workout()
myWorkout.date = currenDate
myWorkout.name = workoutName
for i in 0 ..< exercises.count {
myWorkout.exercise = exercises[i]
myWorkout.sets = sets[i]
myWorkout.reps = reps[i]
myWorkout.kg = kg[i]
myWorkout.notes = notes[i]
realm.add(myWorkout)
}
try! realm.write {
realm.add(myWorkout)
}
}
The problem in this case is that when running the realm.write ... it only adds the last value from the for i in 0 function. I tried putting the realm.write function inside of the for i in 0 loop, but then it crashes. Each of the arrays contains equal numbers of objects. Any ideas?
You can try this code:
var myWorkouts:[Workout] = []
for i in 0 ..< exercises.count {
let myWorkout = Workout()
myWorkout.date = currenDate
myWorkout.name = workoutName
myWorkout.exercise = exercises[i]
myWorkout.sets = sets[i]
myWorkout.reps = reps[i]
myWorkout.kg = kg[i]
myWorkout.notes = notes[i]
myWorkouts.append(myWorkout)
}
try! realm.write {
realm.add(myWorkouts)
}
You should only add and write once if possible for performance optimisation.
Hope this helps.
I'm making an app for airports and I'm getting an array of data from one api, like so:
"data":[
{"id":"001","code":"ABZ","name":"Aberdeen","country":"United Kingdom"},
{"id":"002","code":"AUH","name":"Abu Dhabi","country":"United Arab Emirates"},
.
.
.
]
AND :
"airports":[
{"from":"001",
"to":["1","3","11","13","12","20","23","27","29","31","33"]
},
.
.
.
]
I have created realm model classes:
class AirportsDataRealm: Object {
#objc dynamic var name: String = ""
#objc dynamic var id: Int = 0
#objc dynamic var code: String = ""
#objc dynamic var country: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class AirportsFromToRealm: Object {
#objc dynamic var fromID: Int = 0
var toID = List<Int>()
override static func primaryKey() -> String? {
return "fromID"
}
}
now I want to save it into realm, I'm using swiftyJSON and I have used for-loop to do it and it is working fine but I think it's taking long time since the array is very long, here is what I've done:
// Airports Data
let countData = json["data"].count
for i in 0...countData - 1{
let airportsDataModel = AirportsDataRealm()
airportsDataModel.code = json["data"][i]["code"].stringValue
airportsDataModel.name = json["data"][i]["name"].stringValue
airportsDataModel.country = json["data"][i]["country"].stringValue
airportsDataModel.id = Int(json["data"][i]["id"].stringValue)!
try! realm.write {
realm.add(airportsDataModel, update: true)
}
}
//Airports FROM-TO
let countFromTo = json["airports"].count
for i in 0...countFromTo - 1{
let fromToDataModel = AirportsFromToRealm()
fromToDataModel.fromID = Int(json["airports"][i]["from"].stringValue)!
let arrayTo = json["airports"][i]["to"].arrayValue.map{ $0.intValue }
fromToDataModel.toID.append(objectsIn: arrayTo)
try! realm.write {
realm.add(fromToDataModel, update: true)
}
}
is there any way to save the whole array in realm in one shot without for-loop?
P.S
"there should be a relation between the two tables because each from 'id' has a list of 'to' id's and the id's are from the data table, for now I managed to create this relations when fetching the data using filters ,, so just ignore this"
Thank you
Simply use map method,
First I needed to add initializers to my object classes and pass json array as a parameter, like so:
class AirportsDataRealm: Object {
#objc dynamic var name: String = ""
#objc dynamic var id: Int = 0
#objc dynamic var code: String = ""
#objc dynamic var country: String = ""
convenience required init(withJSON json : JSON) {
self.init()
self.name = json["name"].stringValue
self.id = json["id"].intValue
self.code = json["code"].stringValue
self.country = json["country"].stringValue
}
override static func primaryKey() -> String? {
return "id"
}
}
class AirportsFromToRealm: Object {
#objc dynamic var fromID: Int = 0
var toID = List<Int>()
convenience required init(withJSON json : JSON) {
self.init()
self.fromID = json["from"].intValue
let toArray = json["to"].arrayValue.map{ $0.intValue }
self.toID.append(objectsIn: toArray)
}
override static func primaryKey() -> String? {
return "fromID"
}
}
Then by using map method the code will look like this:
func updateAirport(json: JSON) {
// Airports Data
let airportsData : [AirportsDataRealm]
let airportsDataJsonArray = json["data"].array
airportsData = airportsDataJsonArray!.map{AirportsDataRealm(withJSON: $0)}
//Airports FROM-TO
let airportsFromTo : [AirportsFromToRealm]
let airportsFromToJsonArray = json["airports"].array
airportsFromTo = airportsFromToJsonArray!.map{AirportsFromToRealm(withJSON: $0)}
//Write To Realm
try! realm.write {
realm.add(airportsData, update: true)
realm.add(airportsFromTo, update: true)
}
}
No for loops anymore ^_^
We are running into a really strange issue with Realm (Swift). If we retrieve an entry immediately after writing it to the db it is completely different from the written one. What could possible cause this. Below is a screenshot from the debugger where it happens. The code to fetch the entry looks like this:
func fetchEntry(assetID: String) throws -> UploadInfo? {
let realm = try Realm()
return realm.objects(UploadInfo.self).filter { $0.assetID == assetID }.first
}
The entry class looks like this:
class UploadInfo: Object {
override static func primaryKey() -> String? {
return "assetID"
}
override static func indexedProperties() -> [String] {
return ["sessionID", "taskID"]
}
#objc dynamic var sessionID: String = ""
#objc dynamic var taskID: Int = 0
#objc dynamic var totalBytesSent: Int64 = 0
#objc dynamic var totalBytesExpectedToSend: Int64 = 0
#objc dynamic var downloadProgress: Float = 0.0
#objc dynamic var uploadProgress: Float = 0.0
#objc dynamic var fileURLPath: String = "" // path of file that is uploaded (i.e. multipart body)
#objc dynamic var path: String = ""
#objc dynamic var assetID: String = "" //PHAsset localIdentifier
#objc dynamic var fileModificationTime: DegooTimestamp = 0
#objc dynamic var fileSize: Int64 = 0 // unprocessedTotalFileDataLength
#objc dynamic var fileChecksumBase64: String = ""
#objc dynamic var fileChecksum: Data = Data(base64Encoded: "")!
var fileURL: URL {
return URL(fileURLWithPath: fileURLPath)
}
func makeCopy() -> UploadInfo {
let ui = UploadInfo()
ui.sessionID = sessionID
ui.taskID = taskID
ui.totalBytesSent = totalBytesSent
ui.totalBytesExpectedToSend = totalBytesExpectedToSend
ui.downloadProgress = downloadProgress
ui.uploadProgress = uploadProgress
ui.fileURLPath = fileURLPath
ui.path = path
ui.assetID = assetID
ui.fileModificationTime = fileModificationTime
ui.fileSize = fileSize
ui.fileChecksumBase64 = fileChecksumBase64
ui.fileChecksum = fileChecksum
return ui
}
}
extension UploadInfo {
var data: Data? {
do {
guard try FileManager.default.isFile(at: self.fileURL) else { return nil }
return try Data(contentsOf: self.fileURL)
} catch {
Log.error(error)
return nil
}
}
var asset: PHAsset? {
return PHAsset.fetchAssets(withLocalIdentifiers: [self.assetID], options: nil).firstObject
}
var shouldBeOptimized: Bool {
guard let asset = self.asset else { return false }
return ImageOptimizer.default.shouldBeReoptimized(width: asset.pixelWidth, height: asset.pixelHeight)
}
func cleanUpUrls() {
for url in urlsToCleanUp {
do {
if FileManager.default.fileExists(atPath: url.absoluteString) {
try FileManager.default.removeItem(at: url)
}
} catch {
Log.error(error)
}
}
}
var urlsToCleanUp: [URL] {
let localAssetPathHelper = LocalAssetPathHelper()
let assetFileName = localAssetPathHelper.fileName(for: URL(fileURLWithPath: self.path))
let multipartBodyFileName = localAssetPathHelper.fileName(for: self.fileURL)
return [
URL(fileURLWithPath: localAssetPathHelper.path(for: multipartBodyFileName)),
URL(fileURLWithPath: localAssetPathHelper.path(for: "/Photos/".appending(assetFileName))),
URL(fileURLWithPath: localAssetPathHelper.path(for: "/Videos/".appending(assetFileName)))
]
}
}
We have tried this on both Realm 3.1.1 and 3.5.0.
I want to save data into realm if the user clicks on a button. Moreover the view should be updated if the user clicks that button. I have the following code:
#IBAction func saveAction(_ sender: UIButton) {
if currentLogWeightTextField.text!.isEmpty || currentLogRepsTextField.text!.isEmpty || currentLogRPETextField.text!.isEmpty {
errorLabel.isHidden = false
return
}
else{
if let weight = Float(currentLogWeightTextField.text!), let reps = Int(currentLogRepsTextField.text!), let rpe = Float(currentLogRPETextField.text!){
errorLabel.isHidden = true
let setToSave = excercisesFromPlan![excerciseCounter].sets[setCounter]
do{
try realm.write{
setToSave.weight = weight
setToSave.repeats = reps
setToSave.rpe = rpe
}
}
catch{
print(error)
}
}
else{
errorLabel.isHidden = false
return
}
if setCounter < excercisesFromPlan![excerciseCounter].sets.count{
setCounter += 1
setupLabels()
print(setCounter)
print(excercisesFromPlan![excerciseCounter].sets.count)
}
else{
let finished = plan!.excercises.count - 1
if excerciseCounter == finished{
performSegue(withIdentifier: SegueIdentifier.finishedWorkout, sender: nil)
return
}
else{
excerciseCounter += 1
setCounter = 1
setupLabels()
}
}
}
}
This is my setupLabel method:
func setupLabels(){
if let excercise = excercisesFromPlan?[excerciseCounter]{
excerciseNameLabel.text = "\(excercise.name)"
setsNumberLabel.text = "\(setCounter)/\(excercise.sets.count)"
}
}
These are the relevant properties:
var excercisesFromPlan: List<Excercise>?
var plan: TrainingPlan?
var excerciseCounter = 0
var setCounter = 1
excercisesFromPlan = plan?.excercises
The plan property is given through a segue.
These are my model classes:
class TrainingPlan: Object {
dynamic var trainingPlanID = NSUUID().uuidString
dynamic var routine: Routine?
dynamic var workout: Workout?
dynamic var selected = false
dynamic var name = ""
dynamic var trainingPlanDescription = ""
dynamic var creationDate = Date(timeIntervalSince1970: 1)
dynamic var lastChangeDate = Date(timeIntervalSince1970: 1)
dynamic var lastUsed = Date(timeIntervalSince1970: 1)
let excercises = List<Excercise>()
override class func primaryKey() ->String?{
return "trainingPlanID"
}
}
class Excercise: Object {
dynamic var excerciseID = NSUUID().uuidString
dynamic var trainingsplan: TrainingPlan?
dynamic var selected = false
dynamic var name = ""
dynamic var excerciseDescription = ""
dynamic var muscleGroup = ""
dynamic var record = 0
dynamic var picture: NSData?
dynamic var copied = false
let sets = List<TrainingSet>()
override class func primaryKey() ->String?{
return "excerciseID"
}
override static func indexedProperties() -> [String] {
return ["name"]
}
}
I have the problem that if I use this code and click the save button, the Labels are updating right and the counter are also working. The only problem is that the else statement
else{
let finished = plan!.excercises.count - 1
if excerciseCounter == finished{
performSegue(withIdentifier: SegueIdentifier.finishedWorkout, sender: nil)
return
}
else{
excerciseCounter += 1
setCounter = 1
setupLabels()
}
}
is never been called. I'm searching for the problem for a few hours now but I can't find it..
Strangely, if I comment out the following from the save function it works perfectly and the else statement is called right:
if let weight = Float(currentLogWeightTextField.text!), let reps = Int(currentLogRepsTextField.text!), let rpe = Float(currentLogRPETextField.text!){
errorLabel.isHidden = true
let setToSave = excercisesFromPlan![excerciseCounter].sets[setCounter]
do{
try realm.write{
setToSave.weight = weight
setToSave.repeats = reps
setToSave.rpe = rpe
}
}
catch{
print(error)
}
}
else{
errorLabel.isHidden = false
return
}
Sorry for so much code.. Does anyone know why this is not working? Thanks in advance!
I'm trying to save my array of objects in Realm, but Realm appears to be saving only the last object.
This is my model class:
class ContactEntry: Entry {
dynamic var contactId: Int = 0
dynamic var email: String? = ""
dynamic var phone: String? = ""
dynamic var building: String? = ""
dynamic var room: String? = ""
dynamic var contactDescription: String? = ""
dynamic var worktime: String? = ""
dynamic var address: String? = ""
dynamic var personEntries: PersonEntry?
}
This is the base class:
class Entry: Object {
dynamic var id: Int = 0
override static func primaryKey() -> String? { return "id" }
}
This is code I'm using for saving:
func createOrUpdate(entities: [Entity]) {
let entries = toEntries(entities)
let realm = try! Realm()
try! realm.write {
realm.add(entries, update: true)
}
}
func toEntry(entity: Contact) -> ContactEntry {
let entry = ContactEntry()
entry.contactId = entity.id
entry.email = entity.email
entry.phone = entity.phone
entry.building = entity.building
entry.room = entity.room
entry.contactDescription = entity.description
entry.worktime = entity.worktime
entry.address = entity.address
entry.personEntries = personDAO.toEntry(entity.person)
return entry
}
func toEntry(entity: Person) -> PersonEntry {
let entry = PersonEntry()
entry.personId = entity.id
entry.firstname = entity.firstname
entry.middlename = entity.middlename
entry.lastname = entity.lastname
entry.photo = entity.photo
return entry
}
I think that it may be because I have relationship in my model, but I'm not sure why they'd be a problem.
I'm using them as described in the Realm documentation.