Recent updates - Story like snapchat - ios

So I have a story like Snapchat, where you see the oldest first. But how can I save where the user saw the last story, so the user can continue to watch from where he left off, instead of watching the whole story from the start again? I have absolute no idea how to do this, any suggestions?
Adding my query code if that is necessarily:
func queryStory(){
let query = PFQuery(className: "myClassStory")
query.whereKey("isPending", equalTo: false)
query.limit = 1000
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (posts: [PFObject]?, error: NSError?) -> Void in
if (error == nil){
// Success fetching objects
for post in posts! {
if let imagefile = post["userFile"] as? PFFile {
self.userFile.append(post["userFile"] as! PFFile)
self.objID.append(post.objectId!)
self.createdAt.append(post.createdAt!)
}
}
print("Done!")
}
else{
print(error)
}
}
}
To detect the current image in the story, i use self.objID.
Thanks in advanced! :)

You could use NSUserDefaults for this. Either save the ID number of the post that they have reached, or an array that stores a value of "seen" or "unseen" for each post.

Related

How to implement Parse query properly to get ordered data

I have below code to build a query out of two queries.
Issue is result is not sorted by updatedAt.
What could be the issue?
let ownerQuery = PFQuery(className: "requests")
ownerQuery.whereKey("owner", equalTo: forUser)
ownerQuery.whereKey("stage", equalTo: "initiated")
let requestQuery = PFQuery(className: "requests")
requestQuery.whereKey("requested_by", equalTo: requestedBy)
requestQuery.whereKey("stage", equalTo: "accepted")
// fetch all request of current user as requestor or lender/seller
let query = PFQuery.orQuery(withSubqueries: [ownerQuery, requestQuery])
query.includeKey("requested_by")
query.includeKey("owner")
query.order(byDescending: "updatedAt")
issue turned out to be code where i was processing the retrieved data. Parse returned sorted result.
I have below code where ordering gets affected. it seems to be because of getDetails() returning in async.
So i have added array sort before returning. I retrieve 20 rows at a time so sorting every array should not be costly i guess.
I had also posted on GitHub. Awaiting confirmation.
query.findObjectsInBackground { (results, error) in
if error == nil {
for result in results! {
group.enter()
let stage = result["stage"] as! String
let requestedBy = result["requested_by"] as! PFUser
DBHelper.getDetails(result["requested_id"] as! String, callbackFunction: { (requestedItem) in
let owner = result["owner"] as! PFUser
let request = Request()
request.requestId = result.objectId
request.item = requestedItem
request.owner = owner
request.lastUpdatedDate = result.updatedAt
requestsFound.append(request)
group.leave()
})
}
group.notify(queue: DispatchQueue.global(qos: .background), execute: {
DispatchQueue.main.async {
requestsFound.sort {(request1:Request, request2:Request) -> Bool in
request1.lastUpdatedDate! < request2.lastUpdatedDate!
}
callbackFunction(requestsFound,nil)
}
})
} else {
// encountered error from Parse
DispatchQueue.main.async {
callbackFunction(requestsFound,error! as NSError) // to represent error at backend server
}
}
} //end of findObjectsInBackground
Try this one:
ownerQuery.order(byAscending: "updatedAt")

Only show friends posts on Parse

new programmer trying to learn Swift and I'm trying to set my app up to only show the current users post on a parse photosharing database. The first method here in theory should add the current user to the "followingWho" array.
override func viewDidLoad() {
super.viewDidLoad()
let userQuery = PFUser.query()
userQuery?.whereKey("username", equalTo: PFUser.currentUser()!.username!)
userQuery?.findObjectsInBackgroundWithBlock ({
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//no error
if let objects = objects {
for object in objects {
let followingWho = object["followingWho"] as! NSArray!
self.loadData(followingWho)
}
}
} else {
//error
NSLog("Error")
}
})
self.tableView.reloadData()
}
then my second method here should display the posts and filter out all but the current users
func loadData(followingWho: NSArray) {
let query = PFQuery(className: "Posts")
query.whereKey("addedBy", containedIn: followingWho as! [PFObject])
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(posts: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
//No error
//let posts = posts as! [PFObject]
if let posts = posts {
for post in posts {
self.images.append(post["Image"] as! PFFile)
self.imageCaptions.append(post["Caption"] as! String)
self.imageDates.append(post["date"] as! String)
self.imageUsers.append(post["addedby"] as! String)
}
self.tableView.reloadData()
}
} else {
//error
NSLog("Error")
}
}
}
But nothing seems to be working. The code compiles and runs but it seems to only pull up a blank screen loading none of the posts.
This could be the problem, although if it is not the problem, it is certainly a problem: you are trying to update the UI from a background thread. findObjectsInBackgroundWithBlock calls its completion block in the background, and updating UI from the background is a big no-no. Instead, call your UI updates on the main thread:
dispatch_async(dispatch_get_main_queue(), {
//Do your UI updates here
})

Can't update Array within a function

Hey I'm working with Swift 2 and I'm trying to make a method that returns an array of strings of IDs downloaded from a database through a query. My problem is that within the function I cannot update my Array, meaning that I can access the downloaded information from the server but I cannot append it to my array for some reason. Or better, I can, but it doesn't really do anything. My array seems to stay empty.
func ATMsAroundMe(myLocation : PFGeoPoint) -> [String]{
var results = [String]()
let query = PFQuery(className: "ATMs")
query.whereKey("location", nearGeoPoint: myLocation, withinMiles: 5)
query.limit = 10
query.findObjectsInBackgroundWithBlock { (atms: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
for atm in atms! {
print(atm.objectId) //Works!
results.append(atm.objectId!) //Doesn't work
}
} else {
// Log details of the failure
}
}
print(results) //Prints "[]"
return results
}
So yeah if you have any suggestion or any idea on what am I doing wrong it'd be really helpful and appreciated if you could let me know.
Thanks.
The reason why results is not updated is because it is updated in another block scope. So updated values persists only in that block scope. To get the updated result you would need to use closures or __block in variable declaration in Objective-c.
which is quite nicely explained here here in BLOCKS VS CLOSURES
The issue here is that the call-
query.findObjectsInBackgroundWithBlock
This is an asynchronous call, and thus, your method simply returns as it does not wait for the results that will be returned by this asynchronous call. Thus you will need to think of an asynchronous API ATMsAroundMe in the form-
func ATMsAroundMe(myLocation : PFGeoPoint, completionHandler:(Bool,[String]?) ->Void){
let query = PFQuery(className: "ATMs")
query.whereKey("location", nearGeoPoint: myLocation, withinMiles: 5)
query.limit = 10
query.findObjectsInBackgroundWithBlock { (atms: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
for atm in atms! {
print(atm.objectId) //Works!
var results = [String]()
results.append(atm.objectId!)
completionHandler(true, results)
}
} else {
// Report the failure
completionHandler(false, nil)
}
}
}
You can now call this API like-
ATMsAroundMe(myLocation){(success :Bool, results:[String]?) in
if(success){
if let results = results {
//Process results
}
}
}
Synchronous solution:
func ATMsAroundMe(myLocation : PFGeoPoint) -> [String]{
var results = [String]()
let query = PFQuery(className: "ATMs")
query.whereKey("location", nearGeoPoint: myLocation, withinMiles: 5)
query.limit = 10
//Declare a semaphore to help us wait until the background task is completed.
let sem = dispatch_semaphore_create(0);
query.findObjectsInBackgroundWithBlock { (atms: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
for atm in atms! {
print(atm.objectId) //Works!
results.append(atm.objectId!)
dispatch_semaphore_signal(sem);
}
} else {
// Log details of the failure
dispatch_semaphore_signal(sem);
}
}
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
print(results) //Should print your results
return results
}
Note Be care full in calling this synchronous API from your main thread, it can potentially stall the main thread until the call returns like any other synchronous calls.

For each loop error in Parse image query

I'm writing a function to query the class Photos with a given Object Id in order to download a photo and set it to the UIImageView "background." I've narrowed the issue down to "for object in objects!" which I've commented in the code below. This seems like standard practice for casting, but the code won't run past this point. It compiles and no errors are thrown, but it fails to print anything past the "for" line, much less set the background.
// set new background image
func imageSet(objId: String) {
var query : PFQuery = PFQuery(className: "Photos")
query.whereKey("objId", equalTo:objId)
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
println("First query")
// last working line
for object in objects! {
println("Won't print here")
// won't pass this point
let userImageFile = object["image"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error:NSError?) -> Void in
if error == nil {
println("Or here")
self.background.image = UIImage(data:imageData!)
}
}
}
}
else {
println("\(error)")
}
}
}
Any tips are greatly appreciated! Thanks!

ios swift parse: orderByAscending ist getting ignored

When I run this query:
var query = PFQuery(className: "CardSet")
query.whereKey("user", equalTo: PFUser.currentUser())
query.includeKey("lesson")
query.orderByAscending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in ........
The results are never sorted by data, in fact they are always sorted by objectId.
What is wrong in my query?
This is my data on parse, sorted by date
This is my output on the device, sorted by objectId...
Had the same issue. Try adding this to your above code in block, it worked for me:
let array:NSArray = self.queryobjectsArray.reverseObjectEnumerator().allObjects
self.queryobjectsArray = NSMutableArray(array: array)
This whole issue ended quite strange...
What I did before, like in other views within the same project, I fetched the data from parse and pinned it to the local storage and called a second method to fetch the data from the local storage. This way I have fast reachable data from local storage and update it in the background for later use.
For some reason, the fetched data from online was sorted by date.
But the fetched data from the local pin was not and that was the reason, why my app displays the data in the wrong timeline.
I was not able to understand or solve this, but I helped myself by removing the local pinning and just grab the data from the internet.
I will show what the original process was:
var cardSetObjects: NSMutableArray! = NSMutableArray()
override func viewDidAppear(animated: Bool) {
self.fetchAllObjectsFromLocalDatastore()
self.fetchAllObjects()
}
func fetchAllObjectsFromLocalDatastore(){
var query = PFQuery(className: "CardSet")
query.fromLocalDatastore()
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil){
var temp: NSArray = objects as NSArray
self.cardSetObjects = temp.mutableCopy() as NSMutableArray
self.tableView.reloadData()
}else{
println(error.userInfo)
}
}
}
func fetchAllObjects(){
var query = PFQuery(className: "CardSet")
query.whereKey("user", equalTo: PFUser.currentUser())
query.includeKey("lesson")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
PFObject.pinAllInBackground(objects, withName:"CardSet", block: nil)
self.fetchAllObjectsFromLocalDatastore()
self.tableView.reloadData()
}else{
println(error.userInfo)
}
}
}
What I did at the end was to remove the fetchAllObjectsFromLocalDatastore method and put the data into the NSMutableArray right in fetchAllObjects.
But I still wonder why I had this sorting issue with this code...
Maybe someone will know...

Resources