Return statement in nested if function - ios

I have been struggling with something for a while.
How can I return something in a nested if function?
The function below has the task of finding out if the userProfile has a verified card or not, if verified == 1 (true) then return true, else return false.
func userHasVerfifiedCard() -> Bool{
let userDocument = users.documentWithID(Meteor.userID!)
if let card = userDocument.valueForKey("profile")!["card"] {
print("has card")
if let verified = card!["verified"] as? Int {
print("card.verified as Int")
if verified == 1{
print("card.verified == 1")
lastFourCreditCardLbl.text = card!["last4"] as? String
return true
}else {
return false
}
}
}

your method won't return anything, if if let card won't work. But it must return a bool in any case.
func userHasVerfifiedCard() -> Bool {
let userDocument = users.documentWithID(Meteor.userID!)
if let card = userDocument.valueForKey("profile")!["card"] {
print("has card")
if let verified = card!["verified"] as? Int {
print("card.verified as Int")
if verified == 1 {
print("card.verified == 1")
lastFourCreditCardLbl.text = card!["last4"] as? String
return true
}
}
}
return false
}

Try this and let me know if it's helps..!
func userHasVerfifiedCard() -> Bool{
let userDocument = users.documentWithID(Meteor.userID!)
if let card = userDocument.valueForKey("profile")!["card"], verified = card!["verified"] as? Int where verified == 1 {
return true
} else {
return false
}
}

Related

Validating appRecieptStoreURL returning status code 21002 on the watchOS

I'm making app for both iPhone and watch. And when I validating receipt on iPhone, it is successfull and possible to get all the previous transitions. But on the watch when I validating the receipt it returns a status code 21002. I use the same code. What should I do to prevent this issue ?
There is the code:
extension IAPManagaer {
public func checkTheReciept(_ complition: #escaping ( _ success: Bool) -> Void = { _ in}) {
self.loadReciept()
guard let receipt = UserDefaultsValues.receipt else {
self.setIsAnyPurchaseOnFalse()
return
}
self.postSubscription(inputModel: SubscriptionModel(receipt: receipt, secret: String(shareSecret), phone: true, watch: true, trial: true), complition)
}
private func loadReciept() {
guard let url = Bundle.main.appStoreReceiptURL else { return }
do {
if UserDefaultsValues.receipt == nil {
recieptRefreshRequest.start()
}
let data = try Data(contentsOf: url)
UserDefaultsValues.receipt = data.base64EncodedString()
} catch let error {
print(error.localizedDescription)
DispatchQueue.main.async {
UserDefaultsValues.isWatchSubPurchased = false
UserDefaultsValues.isPhoneSubPurchased = false
}
}
}
private func setIsAnyPurchaseOnFalse() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.isDataLoded = true
}
if UserDefaultsValues.subscriptionInfoModel != nil {
DispatchQueue.main.async {
self.isPhoneSubPurchased = !(Date().timeIntervalSince1970 - (UserDefaultsValues.subscriptionInfoModel!.expirePhone ?? 0)/1000 > 0)
self.isWatchSubPurchased = !(Date().timeIntervalSince1970 - (UserDefaultsValues.subscriptionInfoModel!.expireWatch ?? 0)/1000 > 0)
self.isPhoneFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel!.isPhoneFreeTrial
self.isWatchFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel!.iswatchFreeTrial
}
} else {
DispatchQueue.main.async {
UserDefaultsValues.subscriptionInfoModel = SubscriptionInfoModel(expirePhone: 0.0, expireWatch: 0.0, isPhoneFreeTrial: false, iswatchFreeTrial: false, isPhonePurchased: false, isWatchPurchased: false)
self.isPhoneSubPurchased = UserDefaultsValues.subscriptionInfoModel?.isPhonePurchased ?? false
self.isWatchSubPurchased = UserDefaultsValues.subscriptionInfoModel?.isWatchPurchased ?? false
self.isWatchFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel?.isWatchPurchased ?? false
self.isPhoneFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel?.isPhonePurchased ?? false
}
}
}
private func postSubscription(inputModel: SubscriptionModel,_ complition: #escaping (_ succes : Bool) -> Void = { _ in }) {
subscriptionAPI?.postSubscription(inputModel: inputModel, completion: { subscribers, status, error in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.isDataLoded = true
}
print("STATUS - \(status?.description)")
guard let subscribers = subscribers, error == nil else {
self.setIsAnyPurchaseOnFalse()
complition(false)
return
}
var isPhoneSubPurchased = false
var isWatchSubPurchased = false
var isPhoneFreeTrial = false
var isWatchFreeTrial = false
var expireDatePhone: Double?
var expireDateWatch: Double?
subscribers.forEach { transaction in
guard let productId = transaction.product_id, let sub = Subscription(rawValue: productId) else { return }
let expireDate = Double(transaction.expires_date_ms ?? "0")!
let isPurchase: Bool = !(Date().timeIntervalSince1970 - expireDate/1000 > 0)
let isTrial = Bool(transaction.is_trial_period ?? "false") ?? false
switch sub.subGroup {
case .iphone :
if !isPhoneSubPurchased {
expireDatePhone = expireDate
}
isPhoneSubPurchased = isPhoneSubPurchased || isPurchase
isPhoneFreeTrial = isPhoneFreeTrial || isTrial
case.watch :
if !isWatchSubPurchased {
expireDateWatch = expireDate
}
isWatchSubPurchased = isWatchSubPurchased || isPurchase
isWatchFreeTrial = isWatchFreeTrial || isTrial
case .both : break
}
}
DispatchQueue.main.async {
UserDefaultsValues.subscriptionInfoModel = SubscriptionInfoModel(expirePhone: expireDatePhone, expireWatch: expireDateWatch, isPhoneFreeTrial: isPhoneFreeTrial, iswatchFreeTrial: isWatchFreeTrial, isPhonePurchased: isPhoneSubPurchased, isWatchPurchased: isWatchSubPurchased)
self.isPhoneFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel!.isPhoneFreeTrial
self.isWatchFreeTrialStarted = UserDefaultsValues.subscriptionInfoModel!.iswatchFreeTrial
self.isPhoneSubPurchased = UserDefaultsValues.subscriptionInfoModel!.isPhonePurchased
self.isWatchSubPurchased = UserDefaultsValues.subscriptionInfoModel!.isWatchPurchased
}
complition(true)
})
}
}

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.

Swift: Using try? to catch Index out of range

so i am making game and there is a grid and you can only place if any of the adjacent blocks are a source block, well if you are trying to place a block in the top grid there's no block above it so an Index out of range error will be thrown. I am trying to catch it but xcode seems to think no error is possible. Am i doing this wrong? I guess I could go to each case and add a catch but I feel like this should work.
copy friendly text if you would like to try it out in your own IDE:
func isValidPlacement(row:Int,col:Int) -> Bool {
if let t = try? tiles[row-1][col], t.isSource {
return true
}
else if let t = try? tiles[row][col-1], t.isSource {
return true
}
else if let t = try? tiles[row+1][col], t.isSource {
return true
}
else if let t = try? tiles[row][col+1], t.isSource {
return true
}
else {
return false
}
}
Runtime errors and returning bools is the Objective-C way! Throw throw throw! 🙀
public extension Collection {
/// - Returns: same as subscript, if index is in bounds
/// - Throws: CollectionIndexingError
func element(at index: Index) throws -> Element {
guard indices.contains(index)
else { throw CollectionIndexingError() }
return self[index]
}
}
extension Collection where Element: Collection {
/// - Returns: same as subscripting, if indices are in bounds
/// - Throws: CollectionIndexingError
func element( at indices: (Index, Element.Index) ) throws -> Element.Element {
try element(at: indices.0).element(at: indices.1)
}
}
/// Thrown when `getElement` is called with an invalid index.
public struct CollectionIndexingError: Error { }
extension Tile {
enum PlacementError: Error {
case invalid
case noSources
}
}
extension Collection where
Index == Int,
Element: Collection, Element.Index == Int, Element.Element == Tile
{
func validatePlacement(row: Index, column: Element.Index) throws {
let tiles = [(-1, 0), (0, -1), (1, 0), (0, 1)].compactMap {
try? element( at: (row + $0.0, column + $0.1) )
}
guard !tiles.isEmpty
else { throw Tile.PlacementError.invalid }
guard tiles.contains(where: \.isSource)
else { throw Tile.PlacementError.noSources }
}
}
In Swift. you can only catch instances of Error that are thrown by code, you can't catch runtime exceptions such as an array bounds violation
You can create your own safeAccess function. You don't say what type is in your array so I will use SomeType as an example
func safeAccess(row:Int, col:Int) -> SomeType? {
guard row >= 0, row < tiles.count else {
return nil
}
guard col >= 0, col < tiles[row].count else {
return nil
}
return tiles[row][col]
}
func isValidPlacement(row:Int,col:Int) -> Bool {
if let t = tiles.safeAccess(row:row-1,col:col), t.isSource {
return true
}
if let t = tiles.safeAccess(row:row,col:col-1),, t.isSource {
return true
}
if let t = tiles.safeAccess(row:row+1,col:col), t.isSource {
return true
}
if let t = tiles.safeAccess(row:row,col:col+1), t.isSource {
return true
}
return false
}
You could also define an extension on Array
extension Array {
func element(at index: Int) -> Element? {
if index >= 0 && index < self.count {
return self[index]
}
return nil
}
}
And to use it:
func isValidPlacement(row:Int,col:Int) -> Bool {
if let tiles = tiles.element(at:row-1), let t = tiles.element(at:col), t.isSource {
return true
}
else if tiles.element(at:row), let t = tiles.element(at:col-1), t.isSource {
return true
}
else if let tiles = tiles.element(at:row+1), let t = tiles.element(at:col), t.isSource {
return true
}
else if let tiles = tiles.element(at:row), let t = tiles.element(at:col+1), t.isSource {
return true
}
else {
return false
}
}
Accessing an index of an array which doesn't exist results in a run time exception. You can't use try here because the array is not throwing anything.
Try adding these two lines at the start of the func and get rid of all of try?
guard row <= tiles.count - 1 else {
return false
}
guard col <= tiles[row].count - 1 else {
return false
}
Also i am assuming, whatever the type array stores here is an optional. if not you can remove if lets too
func isValidPlacement(row:Int,col:Int) -> Bool {
guard row <= tiles.count - 1 else {
return false
}
guard col <= tiles[row].count - 1 else {
return false
}
if let t = tiles[row-1][col], t.isSource {
return true
}
else if let t = tiles[row][col-1], t.isSource {
return true
}
else if let t = tiles[row+1][col], t.isSource {
return true
}
else if let t = tiles[row][col+1], t.isSource {
return true
}
else {
return false
}
}

Update TableViewCell with Asynchronous data

I have a tableViewCell that contains 8 images total divided into two blocks (4 images in each block). These images are downloaded asynchronously and stored into an array and then used in the the tableViewCell's cellForRowAtIndexPath to populate the images. I reload the tableView when all the images for one block has been added to the array in the dictionary (groupTOImages). The way I am doing it, I am getting out of order inconsistent results with the loading of the data. Some images are loaded into places where they shouldn't be. Is there a way to download the images and get consistent results in the tableViewCell.
var groupNames = [NSManagedObject]()
var groupTOPeople = [NSManagedObject: [String]]()
var groupTOImages = [NSManagedObject: [UIImage]]()
func getGroups() {
...
for group in groupNames {
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
print(picUrl)
ImageLoader.sharedLoader.imageForUrl(picUrl) { (image, url) -> () in
self.groupTOImages[group]?.append(image!)
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(UIImage())
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
}, failure: nil )
}
}
}
var counter = 0
var groupCount = 0
var groupCounter = 0
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellInfo = GroupCellsArray[indexPath.section]
...
case .userGroups:
let cell = tableView.dequeueReusableCellWithIdentifier(cellInfo.description, forIndexPath: indexPath) as! GroupTableViewCell
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
switch counter {
case 0:
cell.firstTitle.text = (gp.valueForKey("name") as! String)
if let ourImages = groupTOImages[gp] {
for image in ourImages {
print(image.description)
print("groupCount \(groupCounter)")
cell.firstUserButtons[groupCount].layer.borderWidth = 0
cell.firstUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter++
groupCounter++
gp = groupNames[groupCounter]
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
cell.secondUserButtons[groupCount].layer.borderWidth = 0
cell.secondUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter = 0
groupCounter++
gp = groupNames[groupCounter]
}
}
}
} else {
cell.secondTitle.text = "Title"
}
default:
break
}
Each row looks like the picture below:
Code using ImageLoader in cellForRowAtIndexPath:
var counter = 0
for group in groupNames {
print("in the second")
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
self.groupTOImages[group]?.append(picUrl)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(nil)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}, failure: nil )
}
}
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
print("counter!!!!")
print("groupCount \(counter)")
switch counter {
case 0:
if let ourImages = groupTOImages[gp] {
cell.firstTitle.text = (gp.valueForKey("name") as! String)
print(cell.firstTitle.text)
for image in ourImages {
if let url = image {
print("I get in here")
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.firstUserButtons[self.groupCount].layer.borderWidth = 0
cell.firstUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
if let url = image {
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.secondUserButtons[self.groupCount].layer.borderWidth = 0
cell.secondUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter = 0
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
} else {
cell.secondTitle.text = "Title"
}
You should replace the self.tableView.reloadData() with
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
Hope this helps!

bad access code 1 using realm when comparing rlmobject to nil

I have a syncing engine with a server that follows this code for created updated and deleted objects
let lastSynchronizationDate = (NSUserDefaults.standardUserDefaults().objectForKey("com.fridge.sync") as [String: NSDate])["skin"]!
query.whereKey("updatedAt", greaterThanOrEqualTo: lastSynchronizationDate)
query.findObjectsInBackgroundWithBlock { (remoteSkins, error) -> Void in
if error != nil {
return
}
if remoteSkins.isEmpty {
return
}
RLMRealm.defaultRealm().transactionWithBlock {
let deletedSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int == 0
}.map {
Skin(forPrimaryKey: $0["color"])
}.filter {
$0 != nil
}.map {
$0!
}
let createdSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int != 0
}.filter {
let skin = Skin(forPrimaryKey: $0["color"])
println(skin.name)
return skin == nil
}.map { (remoteSkin) -> Skin in
let remoteSkinModel = RemoteSkinModel(remoteSkin)
let skin = Skin()
skin.skinModel = remoteSkinModel // Error
return skin
}
let updatedSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int != 0
}.map {
($0, Skin(forPrimaryKey: $0["color"]))
}.filter {
$0.1 != nil
}.map {
$0.1.skinModel = RemoteSkinModel($0.0)
}
RLMRealm.defaultRealm().deleteObjects(deletedSkins)
RLMRealm.defaultRealm().addObjects(createdSkins)
}
}
My skin model:
class Skin: RLMObject {
dynamic var name: String = ""
dynamic var hexString: String = ""
var skinModel: SkinModel! {
didSet {
name = skinModel.name ?? oldValue.name ?? ""
hexString = skinModel.hexString ?? oldValue.name ?? ""
}
}
override class func primaryKey() -> String {
return "hexString"
}
override class func ignoredProperties() -> [AnyObject] {
return ["skinModel"]
}
func save() {
}
}
protocol SkinModel {
var name: String { get }
var hexString: String { get }
}
class RemoteSkinModel: SkinModel {
let remoteSkin: PFObject
let name: String
let hexString: String
init(_ remoteSkin: PFObject) {
self.remoteSkin = remoteSkin
self.name = remoteSkin["name"] as? String ?? ""
self.hexString = remoteSkin["color"] as? String ?? ""
}
}
The first the engine runs everything goes well, but the next time it pops the bad access error when comparing if the realm object is nil or not in the createdSkins' code.
Any idea as to why this would happen?
Thanks in advance
What happens if you force skin to be an optional?
let skin: Sin? = Skin(forPrimaryKey: $0["color"])
if let skin = skin {
println(skin.name)
}
return skin == nil
I think the Swift compiler may be preventing checks to nil because Skin(forPrimaryKey:) should be a failable initializer, but Realm can't mark that as such (only Apple code can have those).
If that's not the issue, let me know and we'll keep troubleshooting this together. (I work at Realm).

Resources