shared database zones cannot be found - cloudkit

I have sucessfully shared a record from private database customzone.
share url Optional(https://www.icloud.com/share/0N9smwzXZ0gfumZv8jyVo7uag)
When I print shared record I get this:
record completion <CKShare: 0x106702100; participants=(
"<CKShareParticipant: 0x2817115e0; hasProtectionInfo=1, isCurrentUser=YES, participantID=E742CBD3-41C9-4A9E-A392-08914E8C1D37, permission=readWrite, role=owner, acceptanceStatus=Accepted, identity=<CKUserIdentity: 0x281815ce0; lookupInfo=<CKUserIdentityLookupInfo: 0x2832ba910; email=vhrao#icloud.com>, cached=0, nameComponents=viswanatha, userID=<CKRecordID: 0x283c6f940; recordName=__defaultOwner__, zoneID=_defaultZone:__defaultOwner__>, contactIdentifiers={\n items = (\n );\n}>>"
), allowsReadOnlyParticipantsToSeeEachOther=YES, publicPermission=none, recordChangeTag=2z, rootRecordID=<CKRecordID: 0x283c39360; recordName=645B675E-121F-4DC8-B86D-8968C8DE7B1C-9651-00000ED7A0D0E95D, zoneID=userProfileZone:__defaultOwner__>, routingKey=0N9, recordID=Share-967C18F4-43C4-4958-9D40-6D890DD205AD:(userProfileZone:__defaultOwner__), recordType=cloudkit.share, etag=2z> and nil
record completion <CKRecord: 0x10bc05ac0; recordID=645B675E-121F-4DC8-B86D-8968C8DE7B1C-9651-00000ED7A0D0E95D:(userProfileZone:__defaultOwner__), recordChangeTag=30, values={
asOfDate = "2020-08-01 20:26:44 +0000";
latitude = "29.9288104125185";
locationId = "1D2A93A8-A22C-4B2A-9EC6-86F646667F3E-8282-00000CF78F38B1DB";
locationType = "Household User";
longitude = "-95.6080147578347";
profileImage = "<CKAsset: 0x10bc05f60; referenceSignature=<01ebb50c 4bd0e618 bb0f4486 b486145b 30f22689 83>, uploadRank=0, path=/private~/Library/Caches/CloudKit/0fce42f4be876f65546aa1b4549b3658e9291963/Assets/B21AB25E-C07A-4D65-9238-61A17B3E6372.01b1f7f738f239ee006815df2bb2896fade0f08229, size=34656, UUID=B21AB25E-C07A-4D65-9238-61A17B3E6372, signature=<01b1f7f7 38f239ee 006815df 2bb2896f ade0f082 29>, wrappedAssetKey=<24 bytes>>";
userType = "Consumer";
}, share=<CKReference: 0x283c38ae0; recordID=<CKRecordID: 0x283c390c0; recordName=Share-967C18F4-43C4-4958-9D40-6D890DD205AD, zoneID=userProfileZone:__defaultOwner__>>, recordType=infrastructure> and nil
Then I fetch RecordZones
func fetchRecordZones(completion: #escaping (CKRecordZoneID?, Error?) -> Void) {
var fetchedRecordZones: [CKRecordZoneID : CKRecordZone]? = nil
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = { (recordZones: [CKRecordZoneID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
completion(nil, error)
return
}
if let recordZones = recordZones {
fetchedRecordZones = recordZones
for recordID in recordZones.keys {
print(recordID.zoneName)
if (recordID.zoneName == Cloud.SharedZone.UserProfile.ZoneName) {
completion(recordID, nil)
}
}
}
completion(nil, nil)
}
fetchZonesOperation.qualityOfService = .utility
self.sharedDB?.add(fetchZonesOperation)
}
I get no recordZones
I go to coud Kit and look at the shared database and fetch zones with fetch with change Token checkbox enabled I get name: userProfileZone owner record name:_9d4825db9b0aa911655e420ec0016129
Looks like it has a zone in shared database. At least seems like, so why am I not getting zones from shared database?
//Sharing code
var lookupInfos = [CKUserIdentity.LookupInfo]()
let creatorID = rootRecord.creatorUserRecordID
self.defaultContainer?.discoverUserIdentity(withUserRecordID: creatorID!) { [weak self] (userIdentity, error) in
guard error == nil else {
if let ckerror = error as? CKError {
self!.aErrorHandler.handleCkError(ckerror: ckerror)
}
completion(false, error)
return
}
if let userIdentity = userIdentity {
lookupInfos.append(userIdentity.lookupInfo!)
let share = CKShare(rootRecord: rootRecord)
share[CKShareTitleKey] = "Infrastructure" as CKRecordValue
//share[CKShareThumbnailImageDataKey] = shoppingListThumbnail as CKRecordValue
share[CKShareTypeKey] = "com.nr2r.infrastructure" as CKRecordValue
if let lookupInfo = userIdentity.lookupInfo {
let op: CKFetchShareParticipantsOperation = CKFetchShareParticipantsOperation(userIdentityLookupInfos: [lookupInfo])
op.fetchShareParticipantsCompletionBlock = { error in
if let error = error {
print("error: ", error)
}
}
op.shareParticipantFetchedBlock = { participant in
participant.permission = .readWrite
share.addParticipant(participant)
let modOp: CKModifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [rootRecord, share], recordIDsToDelete: nil)
modOp.savePolicy = .ifServerRecordUnchanged
modOp.perRecordCompletionBlock = {record, error in
print("record completion \(record) and \(String(describing: error))")
}
modOp.modifyRecordsCompletionBlock = {records, recordIDs, error in
guard let ckrecords: [CKRecord] = records, let record: CKRecord = ckrecords.first, error == nil else {
print("error in modifying the records " + error!.localizedDescription)
completion(false, error)
return
}
if let records = records {
for record in records {
print ("recordType: \(record.recordType)")
if (record.recordType == "cloudkit.share") {
self!.sharedCKRecordZoneID = record.recordID.zoneID
}
print ("recordName: \(record.recordID.recordName)")
print ("zoneID: \(record.recordID.zoneID.zoneName)")
print ("zoneID: \(record.recordID.zoneID.ownerName)")
}
}
if let anURL = share.url {
print("share url \(String(describing: share.url))")
completion(true, nil)
}
}
self?.privateDB?.add(modOp)
}
self?.defaultContainer?.add(op)
}
} else {
completion(false, nil)
}
}
More edits to show how to retrieve shared record:
let op = CKFetchShareMetadataOperation(shareURLs: [aURL])
op.perShareMetadataBlock = { shareURL, shareMetadata, error in
if let shareMetadata = shareMetadata {
if shareMetadata.participantStatus == .accepted {
let query = CKQuery(recordType: Cloud.Entity.Infrastructure, predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
let zone = CKRecordZoneID(zoneName: Cloud.PrivateZone.UserProfile.ZoneName, ownerName: (shareMetadata.ownerIdentity.userRecordID?.recordName)!)
self.sharedDB?.perform(query, inZoneWith: zone, completionHandler: { (records, error) in
if let ckerror = error as? CKError {
self.aErrorHandler.handleCkError(ckerror: ckerror)
completion(nil, error)
} else if let records = records, let firstRecord = records.first {
completion(firstRecord, nil)
}
})
}
}
Fetching shared database zones return zero
self.sharedDB?.fetchAllRecordZones(completionHandler: { (ckrecordZones, error) in
guard error == nil else {
if let ckError = error as? CKError {
self.aErrorHandler.handleCkError(ckerror: ckError)
}
completion (nil, error)
return
}
if let recordZones = ckrecordZones {
for i in 0 ..< recordZones.count{
// find the zone you want to query
if recordZones[i].zoneID.zoneName == Cloud.SharedZone.UserProfile.ZoneName {
completion (recordZones[i].zoneID, nil)
}
}
}
completion (nil, nil)
})

Related

Swift - Fetch elements from Firestore

I have a problem with this function:
func fetchGameFromDB(completionHandler: #escaping ([GamesObject]) -> Void) {
db.collection("games").getDocuments { (querySnapshot, err) in
if let err = err {
print("Error: \(err)")
} else {
self.gameObject = []
for document in querySnapshot!.documents {
print("document \(document.data())")
if let name = document.data()["name"] as? String {
let docRef = self.db.collection("games").document(name)
docRef.getDocument { document, error in
if let document = document {
let data = document.data()
let name = data?["name"] as? String ?? ""
let urlStanding = data?["urlStanding"] as? String ?? ""
let img = data?["gameImg"] as? String ?? ""
let urlUpcoming = data?["urlUpcoming"] as? String ?? ""
self.gameObject.append(GamesObject(name: name, gameImg: img, urlStanding: urlStanding, urlUpcoming: urlUpcoming))
// here i have elements in gameObject
}
// here i have elements in gameObject
}
// here gameObject = []
}
// here gameObject = []
}
completionHandler(self.gameObject)
// here gameObject = []
}
}
}
I get my data well and I add it to my array but when I get to the completionHandler the array is empty.
I find solution, i check if gameObject.count == querySnapshot?.count then I use my completionHandler
func fetchGameFromDB(completionHandler: #escaping ([GamesObject]) -> Void) {
db.collection("games").getDocuments { (querySnapshot, err) in
if let err = err {
print("Error: \(err)")
} else {
self.gameObject = []
querySnapshot?.documents.forEach({ (document) in
if let name = document.data()["name"] as? String {
let docRef = self.db.collection("games").document(name)
docRef.getDocument { document, error in
if let document = document {
let data = document.data()
let name = data?["name"] as? String ?? ""
let urlStanding = data?["urlStanding"] as? String ?? ""
let img = data?["gameImg"] as? String ?? ""
let urlUpcoming = data?["urlUpcoming"] as? String ?? ""
self.gameObject.append(GamesObject(name: name, gameImg: img, urlStanding: urlStanding, urlUpcoming: urlUpcoming))
if self.gameObject.count == querySnapshot?.count {
completionHandler(self.gameObject)
}
}
}
}
})
}
}
}
the first answer there is no problem as long as the missing documents do not exist. but, that cannot be escaped if any of the documents are missing.
how about use to 'DispatchGroup' ?
func fetchGameFromDB(completionHandler: #escaping([GamesObject]) -> Void) {
db.collection("games").getDocuments { (querySnapshot, error) in
guard let docs = querySnapshot?.documents, !docs.isEmpty else {
if let error = error {
print(error)
}
return
}
let group = DispatchGroup()
docs.forEach { doc in
group.enter()
guard let name = doc.data()["name"] as? String else {
group.leave()
return
}
let docRef = self.db.collection("games").document(name)
docRef.getDocument { document, error in
if let document = document, let data = document.data() {
//do something...
gameObjects.append(GamesObject(...)) //init object
}
group.leave()
}
}
group.notify(queue: .main) {
completionHandler(gameObjects)
}
}
}

Am I using firebase api incorrectly?

Whenever paging in tableview, the view model is running fetchDataRx. It works well, but I don't think it's right to sort the entire data every time you paginate and call the addSnapShotListener. If my code is not correct, how can I correct it?
// MARK: ViewController.swift
timeLineTableView.rx.didScroll
.withLatestFrom(viewModel.activated)
.subscribe(onNext: { [weak self] isActivated in
if !isActivated {
guard let self = self else { return }
let position = self.timeLineTableView.contentOffset.y
if position > self.timeLineTableView.contentSize.height - 100 - self.timeLineTableView.frame.size.height {
self.viewModel.fetchPosts.onNext(())
}
}
})
.disposed(by: disposeBag)
//MARK: ViewModel.swift
let fetchPosts: AnyObserver<Void>
let fetching = PublishSubject<Void>()
fetchPosts = fetching.asObserver()
fetching
.do(onNext: { _ in activating.onNext(true) })
.withLatestFrom(posts)
.map { $0.count }
.flatMap{ (count) -> Observable<[post]> in
fireBaseService.fetchDataRx(startIdx: count) }
.map { $0.map { ViewPost(post: $0) } }
.do(onNext: { _ in activating.onNext(false) })
.do(onError: { err in error.onNext(err) })
.subscribe(onNext: { newPosts in
let oldData = posts.value
posts.accept(oldData + newPosts)
})
.disposed(by: disposeBag)
//MARK: FirebaseService.swift
protocol FirebaseServiceProtocol {
func fetchDataRx(startIdx: Int) -> Observable<[post]>
func fetchData(startIdx: Int, completion: #escaping (Result<[post], Error>) -> Void)
}
class FireBaseService: FirebaseServiceProtocol {
func fetchDataRx(startIdx: Int) -> Observable<[post]> {
return Observable.create { (observer) -> Disposable in
self.fetchData(startIdx: startIdx) { result in
switch result {
case .success(let data):
observer.onNext(data)
case .failure(let error):
observer.onError(error)
}
observer.onCompleted()
}
return Disposables.create()
}
}
func fetchData(startIdx: Int, completion: #escaping (Result<[post], Error>) -> Void) {
let db = Firestore.firestore()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm"
if startIdx == 0 {
DispatchQueue.global().async {
let first = db.collection("lolCourt")
.order(by: "date")
.limit(to: 8)
var nextPosts = [post]()
first.getDocuments() { (querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error)")
} else {
for document in querySnapshot!.documents {
guard let url = document.data()["url"] as? String else {
continue
}
guard let champion1 = document.data()["champion1"] as? String else {
continue
}
guard let champion1Votes = document.data()["champion1Votes"] as? Double else {
continue
}
guard let champion2 = document.data()["champion2"] as? String else {
continue
}
guard let champion2Votes = document.data()["champion2Votes"] as? Double else {
continue
}
guard let text = document.data()["text"] as? String else {
continue
}
guard let date = document.data()["date"] as? Double else {
continue
}
nextPosts.append(post(url: url,
champion1: champion1,
champion1Votes: champion1Votes,
champion2: champion2,
champion2Votes: champion2Votes,
text: text,
date: formatter.string(from: Date(timeIntervalSince1970: date))))
}
}
completion(.success(nextPosts))
}
}
}
else {
DispatchQueue.global().async {
let first = db.collection("lolCourt")
.order(by: "date")
.limit(to: startIdx)
first.addSnapshotListener { (snapshot, error) in
guard let snapshot = snapshot else {
print("Error retrieving : \(error.debugDescription)")
return
}
guard let lastSnapshot = snapshot.documents.last else {
return
}
let next = db.collection("lolCourt")
.order(by: "date")
.start(afterDocument: lastSnapshot)
.limit(to: 8)
var nextPosts = [post]()
next.getDocuments() { (querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error)")
} else {
for document in querySnapshot!.documents {
guard let url = document.data()["url"] as? String else {
continue
}
guard let champion1 = document.data()["champion1"] as? String else {
continue
}
guard let champion1Votes = document.data()["champion1Votes"] as? Double else {
continue
}
guard let champion2 = document.data()["champion2"] as? String else {
continue
}
guard let champion2Votes = document.data()["champion2Votes"] as? Double else {
continue
}
guard let text = document.data()["text"] as? String else {
continue
}
guard let date = document.data()["date"] as? Double else {
continue
}
nextPosts.append(post(url: url,
champion1: champion1,
champion1Votes: champion1Votes,
champion2: champion2,
champion2Votes: champion2Votes,
text: text,
date: formatter.string(from: Date(timeIntervalSince1970: date))))
}
}
completion(.success(nextPosts))
}
}
}
}
}
}
I think you are doing it wrong... I would expect to see something more like this:
class FireBaseService {
func getPage<T>(query: Query? = nil, build: #escaping ([String: Any]) -> T) -> Observable<([T], nextPage: Query?)> {
Observable.create { observer in
let db = Firestore.firestore()
let page = query ?? db.collection("lolCourt")
.order(by: "date")
.limit(to: 8)
let listener = page
.addSnapshotListener { snapshot, error in
guard let snapshot = snapshot else { observer.onError(error ?? RxError.unknown); return }
let items = snapshot.documents.map { build($0.data()) }
if let lastSnapshot = snapshot.documents.last {
let next = page
.start(afterDocument: lastSnapshot)
observer.onSuccess((items, nextPage: next))
}
else {
observer.onSuccess((items, nextPage: nil))
}
}
return Disposables.create { listener.remove() }
}
}
}
Use the above in your favorite state machine system. Here is an example using my CLE library.
// in view controller
let fireBaseService = FireBaseService()
let activityIndicator = ActivityIndicator()
let errorRouter = ErrorRouter()
func getPage(nextPage: Query?) -> Observable<([Post?], nextPage: Query?)> {
fireBaseService.getPage(query: nextPage, build: Post.init(dict:))
.rerouteError(errorRouter)
.trackActivity(activityIndicator)
}
let posts = cycle(
inputs: [
getPage(nextPage: nil).map(ViewModel.Input.response),
timeLineTableView.rx.reachedBottom(offset: 20).map(to: ViewModel.Input.next)
],
initialState: ([Post?](), nextPage: Query?.none),
environment: getPage(nextPage:),
reduce: ViewModel.reduce(state:input:getPage:)
)
.map { $0.0.compactMap { $0 } }
and the view model:
enum ViewModel {
enum Input {
case response([Post?], nextPage: Query?)
case next
}
static func reduce(state: inout ([Post?], nextPage: Query?), input: Input, getPage: #escaping (Query) -> Observable<([Post?], nextPage: Query?)>) -> Observable<Input> {
switch input {
case let .response(posts, nextPage):
state.0 += posts
state.nextPage = nextPage
case .next:
guard let nextPage = state.nextPage else { break }
return getPage(nextPage)
.map(Input.response)
}
return .empty()
}
}

How do I set the record name myself when recording on CloudKit?

I can change the record name on the website. I couldn't find a way with the code.
let cloudsave = CKRecord(recordType: "iEmotion")
let recordName = CKRecord.ID(recordName: "1")
privateDatabase.save(cloudsave) { (savedRecord, error) in
if error == nil {
print("SUCCESSFUL") }
else {"ERROR"}
}
I don't want it saved as a UUID.
This should help:
let recordName = CKRecord.ID(recordName: "1")
let cloudsave = CKRecord(recordType: "iEmotion", recordID: recordName)
privateDatabase.save(cloudsave) { (savedRecord, error) in
if error == nil {
print("SUCCESSFUL") }
else {"ERROR"}
}

CloudKit CKFetchRecordsOperation blocks

I'm fetching some cloud records using CKFetchRecordsOperation.
operation.perRecordCompletionBlock closure has a query to get some children records, but i noticed that operation.completionBlock closure is called before perRecordCompletionBlock completes his job. So, where should i call my completion closure which informs everything is done with that operation?
func getResidents(completion: #escaping (_ residents: [Resident]?, _ error: Error?) -> Void) {
var residents = [Resident]()
let recordNames = ["a56e39ad-9078-43b2-b699-5b9faa233f0d",
"e842daaa-3ff2-434b-9d50-3f14eb7e46d5",
"5cf075ad-d78a-4cea-872e-6b062781f14c",
"8e9fdbbb-cf06-486f-9fae-8be13abe2357",
"78b0cc19-9e33-4755-b199-7098fa319368",
"2d9bee21-d268-46cc-84e1-f7784495aac2",
"ae1da81b-bc1d-4e83-b145-c06882dc2203",
"3e13ed1e-e007-4ece-9a6c-8c09d638d6b3",
"78c224ab-e836-48c9-8c1c-f10bd4907457"
]
func getRecordIDs(names: [String]) -> [CKRecordID] {
var IDs = [CKRecordID]()
for name in names {
IDs.append(CKRecordID(recordName: name))
}
return IDs
}
let operation = CKFetchRecordsOperation(recordIDs: getRecordIDs(names: recordNames))
operation.perRecordCompletionBlock = { record, recordID, error in
if error != nil {
completion(nil, error)
} else {
if let record = record {
// Query debts (resident children)
let predicate = NSPredicate(format: "Resident = %#", record.recordID)
let query = CKQuery(recordType: Constants.RecordType.Debt, predicate: predicate)
self.publicCloudDB.perform(query, inZoneWith: nil) { records, error in
if error != nil {
// Retain the record IDs for failed fetches
completion(nil, error)
} else {
var debts = [Debt]()
if let debtRecords = records {
for item in debtRecords {
if let debt = Debt.parse(record: item) {
debts.append(debt)
}
}
}
if var resident = Resident.parse(record: record) {
resident.debts = debts
residents.append(resident)
print(resident)
}
}
}
}
}
}
operation.completionBlock = {
completion(residents, nil)
}
operation.allowsCellularAccess = true
operation.database = publicCloudDB
operation.start()
}

Querying private database in swift for user details

I'm trying to save and store the user's data, then retrieve it and check for a value, pushing the corresponding view controller.
However, despite only having 4 user records in my cloudkit dashboard, i'm getting 33 results, forcing me to change my code and preventing it from working.
This was my original code:
let container = CKContainer.defaultContainer()
let privateDB = container.privateCloudDatabase
let resultPredicate = NSPredicate(format: "TRUEPREDICATE")
let query = CKQuery(recordType: "UserData", predicate: resultPredicate)
query.sortDescriptors = [NSSortDescriptor(key: "MODIFIED", ascending: false)]
privateDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in
if error != nil {
print("\(error)")
}
else{
for record in results! {
self.weight = record["weight"] as? Int
self.height = record["height"] as? Int
self.age = record["age"] as? Int
self.gender = record["genderFemale"] as? Int
if self.weight == nil {
print("push weightVC")
let weightVC = WeightViewController()
self.navigationController?.pushViewController(weightVC, animated: false)
}
else if self.height == nil {
print("push heightVC")
let heightVC = HeightViewController()
self.navigationController?.pushViewController(heightVC, animated: false)
}
else if self.age == nil {
print("push ageVC")
let ageVC = DOBViewController()
self.navigationController?.pushViewController(ageVC, animated: false)
}
else if self.gender == nil{
print("push genderVC")
let genderVC = GenderViewController()
self.navigationController?.pushViewController(genderVC, animated: false)
}
else{
let planVC = PlanOriginViewController()
self.navigationController?.pushViewController(planVC, animated: false)
}
I was forced to change it to this:
privateDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in
if error != nil {
print("\(error)")
}
else{
print("\(results?.count)")
for record in results! {
self.weight = record["weight"] as? Int
self.height = record["height"] as? Int
self.age = record["age"] as? Int
self.gender = record["genderFemale"] as? Int
self.arrayOfUserData?.addObject(record)
print("record added")
}
}
}
print(arrayOfUserData)
if arrayOfUserData != nil{
let ckRecord = arrayOfUserData![0]
self.weight = ckRecord["weight"] as? Int
self.height = ckRecord["height"] as? Int
self.age = ckRecord["age"] as? Int
self.gender = ckRecord["genderFemale"] as? Int
if self.weight == nil {
print("push weightVC")
let weightVC = WeightViewController()
self.navigationController?.pushViewController(weightVC, animated: false)
}
else if self.height == nil {
print("push heightVC")
let heightVC = HeightViewController()
self.navigationController?.pushViewController(heightVC, animated: false)
}
else if self.age == nil {
print("push ageVC")
let ageVC = DOBViewController()
self.navigationController?.pushViewController(ageVC, animated: false)
}
else if self.gender == nil{
print("push genderVC")
let genderVC = GenderViewController()
self.navigationController?.pushViewController(genderVC, animated: false)
}
else{
let planVC = PlanOriginViewController()
self.navigationController?.pushViewController(planVC, animated: false)
}
} else {
}
However, this doesn't work as well. XCode is skipping over the privateDB query block and going straight to the line print(arrayOfUserData), before returning to the privateDB query.
Thanks!
You issue is that you are assuming that your file is single threaded. What you want it to evaluate What fields are not filled in once you have received a results from the database query. What you need is a completion block. This lets you query the data base and then evaluate the results after. I would do something around these lines.
first add a completion handler that gives you a user object back. I assume you have a user defined should look something like this
struct User{
weight:Int
height:Int
age:Int
gender:Sting
}
add your completion handler in your Query Method.
privateDB.performQuery(query, inZoneWithID: nil, completion:([User])) { (results, error) -> Void in
let resutltData = results.value as [String:AnyObject] ?? [:]
let users : [User] = resutltData.flatMap { record in
let weight = record["weight"] as? Int ?? ""
let height = record["height"] as? Int ?? ""
let age = record["age"] as? Int ?? ""
let gender = record["gender"] as? String ?? ""
}
completion(user)
}
now when you call privateDB.performQuery you should save it in a variable and preform your checks there. Something like this:
func ProcessUsers(){
let users = privateDB.performQuery(query, inZoneWithID: nil, completion:{ (User) in
self.user = User
switch user{
case .weight:
if .weight == "" {
print("push weightVC")
let weightVC = WeightViewController()
self.navigationController?.pushViewController(weightVC, animated: false) } else {
fallthrough
}
case .height:
if .height == "" {
print("push heightVC")
let heightVC = heightViewController()
self.navigationController?.pushViewController(heightVC, animated: false) } else {
fallthrough
}
case .age:
if .age == "" {
print("push ageVC")
let ageVC = ageViewController()
self.navigationController?.pushViewController(ageVC, animated: false) } else {
fallthrough
}
case .gender:
if .gender == "" {
print("push genderVC")
let genderVC = genderViewController()
self.navigationController?.pushViewController(genderVC, animated: false) } else {
fallthrough
}
Let me know if you have any more questions about this. I hope it helps.