Swift - How to populate array - ios

I want to send a post request to my API but I am having some issues with mapping.
The user starts on VCA and sees a list of users that is retrieved via GET request, the user can tap on a cell and see the details (VCB). on VCB, you can tap a cell again, and you get an action sheet which will update that status to available or unavailable. The issue I have is to populate the dailyInjuryStatus array in the POST request.
Get request model:
struct DailyInjuryIllnessPlayer: Hashable, Codable {
var playerId: Int
var playerName: String?
var numberOfStatusMissingDays: Int
var entries: [Entry]
func hash(into hasher: inout Hasher) {
hasher.combine(playerId)
}
static func == (lhs: DailyInjuryIllnessPlayer, rhs: DailyInjuryIllnessPlayer) -> Bool {
return lhs.playerId == rhs.playerId
}
}
struct Entry: Codable {
var injuryIllnessId: Int
var injuryIllnessName: String?
var statusDate: Date
var modifiedBy: String?
var status: String?
var playerStatusId: Int
var parentEventId: Int?
}
The model for the POST
struct CreateDailyInjuryIllnessNote: Encodable {
var teamId: UInt32
var dailyInjuryIllnessStatus: [DailyInjuryIllnessStatus]
}
struct DailyInjuryIllnessStatus: Encodable {
var iIeventId: UInt32
var effectiveDate: Date
var eventStatusId: UInt32
var playerId: UInt32
}
The code I am using for the request (Extracting the values from the screen to send to the API):
private extension DailyInjuryIllnessAPI.Model.Request.CreateDailyInjuryIllnessNote {
static func from(playerId: Int?, statusNote: DailyInjuryIllnessPlayer) -> Self? {
guard let playerId = playerId else { return nil }
let teamId = getTeamId(from: statusNote)
// Here is the issue, I can populate teamId, but I cannot populate dailyInjuryIllnessStatus.
return .init(teamId: UInt32(teamId), dailyInjuryIllnessStatus: <#T##[DailyInjuryIllnessAPI.Model.Request.DailyInjuryIllnessStatus]#>)
}
private static func getTeamId(from model: DailyInjuryIllnessPlayer) -> Int {
let answer = model.playerId
return answer
}
private static func getEventId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = 1
for eventId in model.entries {
answer = eventId.injuryIllnessId
}
return answer
}
private static func getEffectiveDate(from model: DailyInjuryIllnessPlayer) -> Date {
var answer = Date()
for date in model.entries {
answer = date.statusDate
}
return answer
}
private static func getEventStatusId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = 1
for statusId in model.entries {
answer = statusId.playerStatusId
}
return answer
}
private static func getPlayerId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = model.playerId
return answer
}
}
The issue as stated in the code is at the return .init Swift expects it to be like the model which has a teamId and an array of DailyInjuryIllnessStatus. How can I put the methods I used to extract those values into the array

Related

Swift - How to make a post request

I am trying to make a POST request using OAuthSwift but I have been stuck. Can someone point me in the right direction?
On ViewController1 we have a list of users, when you tap on a user, you get to ViewController2 which has the details for the user. If you tap a cell, you get an action sheet which you can change a user status. Once you are done, you tap 'save' and the save button should make a post request to the API.
I am lost on how to do this, here is what I have so far.
The Model for GET Request
struct DailyInjuryIllnessPlayer: Hashable, Codable {
var playerId: Int
var playerName: String?
var numberOfStatusMissingDays: Int
var entries: [Entry]
func hash(into hasher: inout Hasher) {
hasher.combine(playerId)
}
static func == (lhs: DailyInjuryIllnessPlayer, rhs: DailyInjuryIllnessPlayer) -> Bool {
return lhs.playerId == rhs.playerId
}
}
struct Entry: Codable {
var injuryIllnessId: Int
var injuryIllnessName: String?
var statusDate: Date
var modifiedBy: String?
var status: String?
var playerStatusId: Int
var parentEventId: Int?
}
The Model for the POST Request:
struct CreateDailyInjuryIllnessNote: Encodable {
var teamId: UInt32
var dailyInjuryIllnessStatus: [DailyInjuryIllnessStatus]
}
struct DailyInjuryIllnessStatus: Encodable {
var iIeventId: UInt32
var effectiveDate: Date
var eventStatusId: UInt32
var playerId: UInt32
}
When a user taps on the user from ViewController1, they segue to ViewController 2 where they can see the details of the user, which would be the [Entry] array from the GET Request.
View Controller2:
The user taps a cell (Entry Object) and they get an action sheet which will change the variable status to whatever title they selected in the action sheet (available, or unavailable).
Next, the user can tap save to send the updated status results to the RESTFUL API.
This is where I am stuck, I am not sure what to do, if you cannot help with the code can you please point me to a tutorial or the steps in pseudocode to help out?
Here is what I tried:
In ViewController2
private extension DailyInjuryIllnessAPI.Model.Request.CreateDailyInjuryIllnessNote {
static func from(playerId: Int?, statusNote: DailyInjuryIllnessAPI.Model.Request.CreateDailyInjuryIllnessNote) {
guard let playerId = playerId else { return nil }
let teamId = statusNote.teamId
// Extract the values and add to dailyInjuryIllnessStatusArray
for statusValues in statusNote.dailyInjuryIllnessStatus {
let iIeventId = statusValues.iIeventId
let effectiveDate = statusValues.effectiveDate
let eventStatusId = statusValues.eventStatusId
let playerId = statusValues.playerId
}
}
}
In the model for the POST request:
func createDailyInjuryIllnessNote(forTeamID teamId: Int, createDailyInjuryIllnessStatus: DailyInjuryIllnessAPI.Model.Request.CreateDailyInjuryIllnessNote, completion: #escaping ((Result<DailyInjuryIllnessPlayer, API.APIError>) -> Void)) {
guard let createDailyInjuryIllnessNoteData = try? API.jsonEncoder.encode(createDailyInjuryIllnessStatus) else {
completion(.failure(.encoding(error: "Could not encode DailyInjuryIllnessAPi.Model.Request.CreateDailyInjuryIllnessNote: \(createDailyInjuryIllnessStatus)")))
return
}
let baseURL = self.configuration.baseURL
let endPoint = baseURL.appendingPathComponent("team/\(teamId)/daily-injury-illness-status")
var headers: OAuthSwift.Headers = [:]
headers["Content-Type"] = "application/json"
API.shared.httpClient.post(endPoint, headers: headers, body: createDailyInjuryIllnessNoteData) { (result) in
switch result {
case .success(let response):
do {
let note = try API.jsonDecoder.decode(DailyInjuryIllnessPlayer.self, from: response.data)
completion(.success(note))
} catch (let error) {
completion(.failure(.decoding(error: error.localizedDescription)))
}
case .failure(let error):
completion(.failure(.unknown(message: error.localizedDescription)))
}
}
}
If anyone can help it would be greatly appreciated.

Swift - toggle model to readonly momentarily

I have a phone number model which looks like this:
import UIKit
import Foundation
struct PhoneValidation : OptionSet {
let rawValue: Int
static let phoneInValid = PhoneValidation(rawValue: 1 << 0)
static let phoneValid = PhoneValidation(rawValue: 1 << 1)
static let smsValidationAttempted = PhoneValidation(rawValue: 1 << 2)
static let smsValidationFailed = PhoneValidation(rawValue: 1 << 3)
static let smsValidationSuccessful = PhoneValidation(rawValue: 1 << 4) // OTP is successfully validated in backend. The field should be non-editable in this duration
static let smsValidationOTPTriggered = PhoneValidation(rawValue: 1 << 5) // OTP validation triggered. The field should be non-editable in this duration
}
class PhonesViewModel: NSCopying {
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
public var phone: String?
public var code: String?
public var countryCode: String?
public var isValid : PhoneValidation?
func copy(with zone: NSZone? = nil) -> Any {
let copy = PhonesViewModel()
copy.phoneType = phoneType
copy.phone = phone
copy.code = code
copy.countryCode = countryCode
copy.isValid = isValid
return copy
}
}
As you can see above the phone model can transition between different states. The SMS validation is available for few countries and for few it is not applicable. So, I plan on setting smsValidationOTPTriggered state when SMS validation is applicable for a country and while the validation is in progress.
What I need here is, while the states smsValidationOTPTriggered or smsValidationSuccessful are set I would not want any module of the application to modify the values(phoneType, phone, code, countryCode) of the model. In other words, I would like the model to switch to a read-only mode while these 2 states are set in model and would like the module to be informed with an error or exception when a modification is attempted.
Is there a best practice already available for what I am trying to achieve here? I have searched before raising this question but did not find any. How can I achieve this?
Thanks,
Raj Pawan Gumdal
How about something like this, I think its better to use property wrappers for your case! The below is not an exact solution but can modify/change to accommodate your need
import UIKit
enum PhoneNumberType {
case mobile
}
enum PhoneValidation {
case phoneInValid
case phoneValid
case smsValidationAttempted
case smsValidationFailed
case smsValidationSuccessful
case smsValidationOTPTriggered
}
struct PhonesViewModel {
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
public var phone: String?
public var code: String?
public var countryCode: String?
public var phoneValidation : PhoneValidation?
func validate(value: [PhoneValidation]) -> Bool {
//add proper check here
return false
}
}
#propertyWrapper
struct Wrapper {
private(set) var value: PhonesViewModel? = nil
var validators: [PhoneValidation] = []
var wrappedValue: PhonesViewModel? {
get { value }
set {
if let model = newValue, model.validate(value: validators) {
value = newValue
print("Value assigned")
} else {
print("Value not assigned")
}
}
}
}
struct SomeOtherClass {
#Wrapper(validators: [PhoneValidation.phoneInValid])
var model: PhonesViewModel?
}
var a = SomeOtherClass()
a.model = PhonesViewModel()
a.model = PhonesViewModel()
You can use a technique with the name "popsicle immutability". An object is initially mutable, but can be "frozen". Modifications for frozen objects are forbidden. In your case PhonesViewModel become frozen when isValid property have value smsValidationOTPTriggered or smsValidationSuccessful.
Let's add Freezable protocol for requirements to objects that can become immutable and conforming for PhonesViewModel:
protocol Freezable: class {
var isFrozen: Bool { get }
}
extension PhonesViewModel: Freezable {
var isFrozen: Bool {
isValid == .smsValidationOTPTriggered || isValid == .smsValidationSuccessful
}
}
Now we must add validation for isFrozen value when a property is assigned. It can be added in property observers like:
...
public var phone: String? {
didSet {
validate()
}
}
...
private func validate() {
assert(!isFrozen)
}
Or using property wrapper:
#propertyWrapper
struct Guarded<Value> {
private var value: Value
init(wrappedValue: Value) {
value = wrappedValue
}
#available(*, unavailable)
var wrappedValue: Value {
get { fatalError("only works on instance properties of classes that conforms to Freezable protocol") }
set { fatalError("only works on instance properties of classes that conforms to Freezable protocol") }
}
static subscript<EnclosingSelf: Freezable>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
object[keyPath: storageKeyPath].value
}
set {
precondition(!object.isFrozen, "Object \(object) is frozen! Modifications are forbidden")
object[keyPath: storageKeyPath].value = newValue
}
}
}
So your class will look like:
class PhonesViewModel: NSCopying {
#Guarded
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
#Guarded
public var phone: String?
#Guarded
public var code: String?
#Guarded
public var countryCode: String?
#Guarded
public var isValid : PhoneValidation?
func copy(with zone: NSZone? = nil) -> Any {
let copy = PhonesViewModel()
copy.phoneType = phoneType
copy.phone = phone
copy.code = code
copy.countryCode = countryCode
copy.isValid = isValid
return copy
}
}

Turning Java object class into Swift class

So I'm learning how to make my Android apps into an iOS app. I've gotten pretty far though I'm having an issue when it comes creating the object. In my android app I read in a csv file and create a FireworkList object that contains info. Here is the code from my Android app:
import java.util.ArrayList;
public class FireworksList{
private ArrayList<Integer> _category = new ArrayList<>();
private ArrayList<String> _name = new ArrayList<>();
private ArrayList<String> _shotCount = new ArrayList<>();
private ArrayList<String> _price = new ArrayList<>();
private ArrayList<String> _description = new ArrayList<>();
private ArrayList<String> _videoUrl = new ArrayList<>();
private ArrayList<Integer> _imageResourceNumber = new ArrayList<>();
private ArrayList<Boolean> _favorite = new ArrayList<>();
private ArrayList<Boolean> _special = new ArrayList<>();
private Integer _specialCategoryNumer =15;
private Integer _nextId;
public FireworksList() {
_nextId=0;
}
public ArrayList<Integer> get_category() {
return _category;
}
public ArrayList<String> get_name() {
return _name;
}
public ArrayList<String> get_shotCount() {
return _shotCount;
}
public ArrayList<String> get_price() {
return _price;
}
public ArrayList<String> get_description() {
return _description;
}
public ArrayList<String> get_videoUrl() {
return _videoUrl;
}
public ArrayList<Integer> get_imageResourceNumber() {
return _imageResourceNumber;
}
public ArrayList<Boolean> get_favorite() {
return _favorite;
}
public void set_favorite(int index, Boolean bool) {
_favorite.set(index,bool);
}
public ArrayList<Boolean> get_special(){return _special;}
public void Add(int cat, String name, String shot, String price, String description, String video, int image, Boolean fav, Boolean special){
_category.add(_nextId,cat);
_name.add(_nextId,name);
_shotCount.add(_nextId,shot);
_price.add(_nextId,price);
_description.add(_nextId,description);
_videoUrl.add(_nextId,video);
_imageResourceNumber.add(_nextId,image);
_favorite.add(_nextId,fav);
_special.add(_nextId,special);
_nextId++;
}
public int Count(){
return _nextId;
}
public FireworksList CategorySort(int position){
FireworksList fireworksListTemp = new FireworksList();
for(int i=0; i<_nextId;i++){
if(position==0){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
else if(position==_category.get(i)){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
else if(position==_specialCategoryNumer&&_special.get(i)==true){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
}
return fireworksListTemp;
}
public FireworksList FavoriteSort(){
FireworksList fireworksListTemp = new FireworksList();
for(int i = 0; i<_nextId;i++){
if(_favorite.get(i)==true){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
}
return fireworksListTemp;
}
public int FindIndex(String name, FireworksList fireworksList){
int found=0;
for(int j=0;j<fireworksList.Count();j++){
if(fireworksList.get_name().get(j).equals(name)){
found=j;
}
}
return found;
}
}
I've started rewriting my code yet I ran into an issue when it came to creating a new Firework list then appending to it with what is needed in the categorySort function. Here is my modified code so far:
class FireworkList {
var _category = [Int]()
var _name = [String]()
var _shotCount = [String]()
var _price = [String]()
var _description = [String]()
var _videioUrl = [String]()
var _imageResourceNumber = [Int]()
var _favorite = [Bool]()
var _special = [Bool]()
private var _specialCategoryNumber : Int = 15
private var _nextId : Int = 0
func FireworksList(){_nextId = 0}
func get_category() -> Array<Int>{return _category}
func get_name() -> Array<String>{return _name}
func get_shotCount() -> Array<String>{return _shotCount}
func get_price() -> Array<String>{return _price}
func get_discription() -> Array<String>{return _description}
func get_videoUrl() -> Array<String>{return _videioUrl}
func get_imageResourceNumber() -> Array<Int>{return _imageResourceNumber}
func get_favorite() -> Array<Bool>{return _favorite}
func get_special() -> Array<Bool>{return _special}
func set_favorite(index : Int, bool : Bool){_favorite[index] = bool}
func add(cat : Int, name : String, shot : String, price : String, description : String, video : String, image : Int, fav : Bool, special : Bool){
_category.insert(cat, at: _nextId)
_name.insert(name, at: _nextId)
_shotCount.insert(shot, at: _nextId)
_price.insert(price, at: _nextId)
_description.insert(description, at: _nextId)
_videioUrl.insert(video, at: _nextId)
_favorite.insert(fav, at: _nextId)
_special.insert(special, at: _nextId)
_nextId+=1
}
func Count()->Int{return _nextId}
func CategorySort(position : Int)-> [FireworkList]{
var fireworkListTemp = [FireworkList]()
for i in 0..._nextId{
if(position == 0){
fireworkListTemp.append(FireworkList())
}
}
return fireworkListTemp
}
}
I'm thankful for any help.
The main issue here is that your java class is poorly designed and you are taking this design with you when writing it in swift. Rather than having a bunch of properties that are collections you should create a struct for those properties and have one array with the struct. (I didn't include all properties to keep the code shorter).
struct Firework {
var category: Int
var name: String
var shotCount: String
var price: String
var special: Bool
}
and then declare it in the main class
class FireworkList {
private var fireworks = [Firework]()
Below is the class with the add, count and categorySort functions to show some examples of how to use this struct. As you can see this means much less code. I also taken the liberty to rename properties and functions to follow recommended swift naming practices.
For the categorySort I have made use of the high order function filter to collect the correct items. If you are going to work with swift I would recommend you learn more about it and the other high order functions like sort, map etc.
Also worth mentioning to someone coming from java is that we don't use get/set methods to the same extent in swift. We most access the property directly like let x = myObject.someValue or myObject.someValue = 10
class FireworkList {
var fireworks = [Firework]()
private let specialCategoryNumber = 15
func add(cat : Int, name : String, shot : String, price : String, special: Bool) {
self.fireworks.append(Firework(category: cat, name: name, shotCount: shot, price: price, special: special))
}
func count() -> Int { return fireworks.count }
func categorySort(position : Int) -> [Firework] {
switch position {
case 0:
return self.fireworks
case specialCategoryNumber:
return self.fireworks.filter { $0.category == specialCategoryNumber && $0.special}
default:
return self.fireworks.filter {$0.category == position}
}
}
}
Here's how I would do it:
public class FireworksList {
private var _category = [Int]()
private var _name = [String]()
private var _shotCount = [String]()
private var _price = [String]()
private var _description = [String]()
private var _videoURL = [String]()
private var _imageResourceNumber = [Int]()
public var favorite = [Bool]()
private var _special = [Bool]()
private let specialCategoryNumber = 15
private var nextId = 0
public var category: [Int] {
get {
return _category
}
}
public var name: [String] {
get {
return _name
}
}
public var shotCount: [String] {
get {
return _shotCount
}
}
public var price: [String] {
get {
return _price
}
}
public var description: [String] {
get {
return _description
}
}
public var videoURL: [String] {
get {
return _videoURL
}
}
public var imageResourceNumber: [Int] {
get {
return _imageResourceNumber
}
}
public var special: [Bool] {
get {
return _special
}
}
public var count: Int {
get {
return nextId
}
}
public func add( cat: Int, name: String, shot: String, price: String, description: String, video: String, image: Int, fav: Bool, special: Bool) {
self._category.append(cat)
self._name.append(name)
self._shotCount.append(shot)
self._price.append(price)
self._description.append(description)
self._videoURL.append(video)
self._imageResourceNumber.append(image)
self.favorite.append(fav)
self._special.append(special)
nextId += 1
}
public func categorySort(at position: Int) -> FireworksList {
let tmp = FireworksList()
for i in 0...nextId {
if position == 0 || position == category[i] ||
(position == specialCategoryNumber && special[i] == true) {
tmp.add(cat: category[i], name: name[i], shot: shotCount[i], price: price[i], description: description[i], video: videoURL[i], image: imageResourceNumber[i], fav: favorite[i], special: special[i])
}
}
return tmp
}
public func favouriteSort() -> FireworksList {
let tmp = FireworksList()
for i in 0...nextId {
if favorite[i] {
tmp.add(cat: category[i], name: name[i], shot: shotCount[i], price: price[i], description: description[i], video: videoURL[i], image: imageResourceNumber[i], fav: favorite[i], special: special[i])
}
}
return tmp
}
// I'm putting this function as static as it isn't directly related to any particular instance of FireworksList at any point of time.
public static func findIndex(name: String, fireworksList: FireworksList) -> Int {
var found = 0
for j in 0...fireworksList.count {
if fireworksList.name[j] == name {
found = j
}
}
return found
}
}
My code simply almost directly follows your Java code.
This is my first time trying to contribute in Stack Overflow, and I hope this can be helpful to you.

Enum case 'case' is not a member of type 'Type'

I'm a complete new-be in programming and have just started learning swift and iOS development.
The idea is to create a kind of 'set game' (a simple card game).
And I'm trying to implement .contains methods to find if an array contains a particular case but I'm stuck - in line 67 (if case Card.Symbol.oval = element) I get this error: Enum case 'oval' is not a member of type 'Card'
What am I doing wrong?
import Foundation
struct Deck {
private (set) var cards = [Card] ()
init() {
for symbol in Card.Symbol.all {
cards.append(Card(symbol: symbol))
}
}
}
struct Card: Hashable {
static func == (lhs: Card, rhs: Card) -> Bool {
return lhs.identifier == rhs.identifier
}
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
var symbol: Symbol
enum Symbol: String {
case squiggle = "■"
case oval = "●"
case diamond = "▲"
static var all = [Symbol.squiggle, .oval, .diamond]
}
private var identifier: Int
private static var identifierFactory = 0
private static func getUniqueIdentifier() -> Int {
identifierFactory += 1
return identifierFactory
}
init(symbol: Symbol) {
self.identifier = Card.getUniqueIdentifier()
self.symbol = symbol
}
}
struct SetGame {
var deck = Deck ()
lazy var cardsInDeck = deck.cards
var cardsOpen = [Card] ()
var cardsChosen = [Card] ()
mutating func chooseCard(at index: Int) {
if cardsChosen.count < 3 {
cardsChosen.append(cardsOpen[index])
}
let itemFound = cardsChosen.contains { element in
if case Card.Symbol.oval = element {
return true
} else {
return false
}
}
}
}

Realm add(_, update: true) removes existing relationships

I am facing an issue where I am unable to keep existing relationships after calling add(_, update: true) function.
I wrote a TaskSync class that is responsible for creating/updating Task objects:
class TaskSync: ISync {
typealias Model = Task
func sync(model: Task) {
let realm = try! Realm()
let inWrite = realm.isInWriteTransaction
if !inWrite {
realm.beginWrite()
}
let _task = realm.object(ofType: Task.self, forPrimaryKey: model.id)
// Persist matches as they are not getting fetched with the task
if let _task = _task {
print("matches: \(_task.matches.count)")
model.matches = _task.matches
}
realm.add(model, update: true)
if _task == nil {
var user = realm.object(ofType: User.self, forPrimaryKey: model.getUser().id)
if (user == nil) {
user = model.getUser()
realm.add(user!, update: true)
}
user!.tasks.append(model)
}
if !inWrite {
try! realm.commitWrite()
}
}
func sync(models: List<Task>) {
let realm = try! Realm()
try! realm.write {
models.forEach { task in
sync(model: task)
}
}
}
}
When a model is to be synced, I check if it already exists in the Realm and if so, I fetch it and try to include the matches property as this one is not included in the model.
Right before the call realm.add(model, update: true), model contains list of matches, however right after the realm.add is executed, the matches list is empty.
Here are the two models:
class Task: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var title: String = ""
dynamic var desc: String = ""
dynamic var price: Float = 0.0
dynamic var calculatedPrice: Float = 0.0
dynamic var location: String = ""
dynamic var duration: Int = 0
dynamic var date: String = ""
dynamic var category: Category?
dynamic var currency: Currency?
dynamic var longitude: Double = 0.0
dynamic var latitude: Double = 0.0
dynamic var state: Int = 0
dynamic var userId: Int = 0
// Existing images
var imagesExisting = List<URLImage>()
// New images
var imagesNew = List<Image>()
// Images deleted
var imagesDeleted = List<URLImage>()
private let users = LinkingObjects(fromType: User.self, property: "tasks")
var user: User?
var matches = List<Match>()
dynamic var notification: Notification?
override static func ignoredProperties() -> [String] {
return ["imagesExisting", "imagesNew", "imagesDeleted", "user", "tmpUser"]
}
override static func primaryKey() -> String? {
return "id"
}
func getImageMain() -> URLImage? {
for image in imagesExisting {
if image.main {
return image
}
}
return imagesExisting.first
}
func getSection() -> Int {
return state
}
func getSectionFieldName() -> String? {
return "state"
}
func getId() -> Int {
return id
}
func getURL() -> URL? {
if let image = getImageMain() {
return image.getResizedURL()
}
return nil
}
func getState() -> TaskOwnState {
return TaskOwnState(rawValue: state)!
}
func getUser() -> User {
return (user != nil ? user : users.first)!
}
}
class Match: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var state: Int = -1
dynamic var priorityOwnRaw: Int = 0
dynamic var priorityOtherRaw: Int = 0
dynamic var user: User!
var messages = List<Message>()
private let tasks = LinkingObjects(fromType: Task.self, property: "matches")
var task: Task?
dynamic var notification: Notification?
override static func primaryKey() -> String? {
return "id"
}
override static func ignoredProperties() -> [String] {
return ["task"]
}
func getId() -> Int {
return id
}
func getSection() -> Int {
return 0
}
func getURL() -> URL? {
if let image = user.getImageMain() {
return image.getResizedURL()
}
return nil
}
func getPriorityOwn() -> PriorityType {
if priorityOwnRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getPriorityOther() -> PriorityType {
if priorityOtherRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getSectionFieldName() -> String? {
return nil
}
func getTask() -> Task {
return (task != nil ? task : tasks.first)!
}
}
I spent hours trying to figure out why I am unable to keep the matches relationship when updating the task. Every advice will be highly appreciated!
This question was also asked upon Realm's GitHub issue tracker. For posterity, here is the solution.
List properties should always be declared as let properties, as assigning to them does not do anything useful. The correct way to copy all objects from one List to another is model.tasks.append(objectsIn: _user.tasks).

Resources