Parse Server Swift Logic for grabbing all items contained in array - swift

I am using parse server with Swift. I am trying to get all matches that where the key "username" is contained in commentUserArray. Comment userArray displays 3 names ["username","username", "username2"].
The query grabs only two values as opposed to three as this looks up only for those two usernames "username" and "username1". However, I need all 3 instances of this. Please help.
var commentImgUrlArray: [NSString] = []
func getPics(_ completionHandler: #escaping () -> Void) {
let query = PFQuery(className: "_User")
query.whereKey("username", containedIn: commentUserArray)
query.findObjectsInBackground(block: { (objects: [PFObject]?, error: Error?) in
if let objects = objects {
for object in objects {
if error == nil {
let imageFile = object["profilePic"] as? PFFileObject
let imageFileString = imageFile?.url as! String
if let url = URL(string: imageFileString) {
let data = try? Data(contentsOf: url)
if let imageData = data {
self.commentImgUrlArray.append(imageFileString as NSString)
print(self.commentImgUrlArray)
}
}
}
}
completionHandler()
}
})
}

So after some trial and error, I have come across the solution.
Delete the original query.contained in as that overrides the rest of the formula.
Ideally, I want to run one query. Not however many on in commentuserarray. As a result, the for in loop should be placed inside the query.find -->
need to grab object for that specific user. Therefore, let pfuser = object["username"] as String
reverse the array to get the proper order --
func getPics(_ completionHandler: #escaping () -> Void) {
let query = PFQuery(className: "_User")
query.findObjectsInBackground(block: { (objects: [PFObject]?, error:
Error?) in
if let objects = objects {
for object in objects {
if error == nil {
for user in self.commentUserArray {
let pfuser = object["username"] as! String
if pfuser == user {
let imageFile = object["profilePic"] as? PFFileObject
let imageFileString = imageFile?.url as! String
if let url = URL(string: imageFileString) {
let data = try? Data(contentsOf: url)
if let imageData = data {
self.commentImgUrlArray.append(imageFileString as
NSString)
print(self.commentImgUrlArray)
}
}
}
}
}
}
self.commentImgUrlArray.reverse()
completionHandler()
}
})
}

Related

Parse Query: order by elements in another Array

Ok I am so close to figuring this out. I have usernames in usernames array. I am trying to do a query where I order the results based off of the sequence in usernames array. I tried using a NSSortDescriptor, but I do not think that it accomplishes this. Thanks
func photoQuery () {
let descriptor: NSSortDescriptor = NSSortDescriptor(key: "usernameArray", ascending: false)
let photoQuery = PFQuery(className: "UserPhoto")
photoQuery.whereKey("username", containedIn: usernameArray)
photoQuery.order(by: descriptor)
photoQuery.findObjectsInBackground(block: { (objects: [PFObject]?, error: Error?) in
if let objects = objects {
for object in objects {
if error == nil {
let userImageFile = object["photo"] as? PFFileObject
let urlString = userImageFile?.url as! String
if let url = URL(string: urlString) {
let data = try? Data(contentsOf: url)
if let imageData = data {
self.urlArray.append(urlString as NSString)
self.cache.setObject(UIImage(data:imageData)!, forKey: urlString as NSString)
}
}
}
}
}
})
}

Array is null after setting data in it

I have a JSON request that gets data from the Darksky API, I get the data properly and it is showing on the screen. However, When i'm trying to set the data from the array I get from the JSON call in another array, it stays empty.
This is my code:
just declaring the array:
var mForecastArray = [Weather]()
this is the function that calls the API:
func getForecast(){
Weather.forecast(withLocation: "37.8267,-122.4233") { (arr) in
DispatchQueue.main.async {
self.mForecastArray = arr
self.mTodayWeather = arr[0]
self.mCollectionView.reloadData()
}
}
}
The weird part is that it does work, and the data do shows on screen, but still, mForecastArray seems null.
This is the API call itself:
static func forecast(withLocation location: String, completion: #escaping ([Weather]) -> ()){
let url = basePath + location
let request = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
var forecastArray: [Weather] = []
if let data = data{
do{
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]{
if let dailyForecast = json["daily"] as? [String:Any]{
if let dailyData = dailyForecast["data"] as? [[String:Any]]{
for dataPoint in dailyData{
if let weatherObject = try? Weather(json: dataPoint){
forecastArray.append(weatherObject)
}
}
}
}
}
}catch{
print(error.localizedDescription)
}
completion(forecastArray)
}
}
task.resume()
}
It's a visual asynchronous illusion.
The static method forecast works asynchronously.
Most likely your code looks like
getForecast()
print(self.mForecastArray)
This cannot work because the array is populated much later.
Move the print line into the completion handler of the static method
func getForecast(){
Weather.forecast(withLocation: "37.8267,-122.4233") { (arr) in
DispatchQueue.main.async {
self.mForecastArray = arr
print(self.mForecastArray)
self.mTodayWeather = arr[0]
self.mCollectionView.reloadData()
}
}
}

In method A, get data from callback in method B?

I have a function that is build to get the latest items from a API. There are several other ones, with different functionality, but they all work the same. It looks like this:
func getLatest(pageNumber: Int) -> Array<Any>{
let urlRequest = URL(string: baseUrl + latestUrl + String(pageNumber))
let requestedData = doRequest(url: urlRequest!, completion: { data -> Void in
// We have the data from doRequest stored in data, but now what?!
})
return allData
}
I also have a async method that handles the requests. That one looks like this:
func doRequest(url: URL, completion: #escaping ([[ApiItem]]) -> ()){
var allItems = [[ApiItem]]()
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do{
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]
let results = json["items"] as? [AnyObject]
for r in results!{
let item = ApiItem(json: r as! [String: Any])
allItems.append([item])
}
completion(allItems)
} catch let jsonError{
print("JSON error: \(jsonError)")
}
}.resume()
The doRequest function works absolutely fine. It gets the data, parses the JSON and send it back to getLatest --> requestedData. The problem right now is, is that getLatest() is a function that needs to return the data that is stored in the data variable of requestedData.
How can I make it so, that the getLatest() function returns the data that is stored in the data in requestedData()?
So I've fixed it by doing this:
In the first method, the one that actually needs the data from the API, I added this:
let trendingData = restApiManager.getLatest(pageNumber: 0, completion: { data -> Void in
let item = data[indexPath.row]
let url = NSURL(string: item.still)
let data = NSData(contentsOf: url as! URL)
if data != nil {
cell.image.image = UIImage(data:data! as Data)
}
})
The getLatest() method looks like this:
func getLatest(pageNumber: Int, completion: #escaping ([ApiItem]) -> ()) {
let urlRequest = URL(string: baseUrl + trendingUrl + String(pageNumber))
let requestedData = doRequest(url: urlRequest!, completion: { data -> Void in
// We have the data from doRequest stored in data
var requestedData = data
completion(requestedData)
})
}
And finally, the doRequest() method looks like this:
func doRequest(url: URL, completion: #escaping ([ApiItem]) -> ()){
var allItems = [ApiItem]()
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do{
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]
let results = json["items"] as? [AnyObject]
for r in results!{
let item = ApiItem(json: r as! [String: Any])
allItems.append(item)
}
completion(allItems)
} catch let jsonError{
print("JSON error: \(jsonError)")
}
}.resume()
}
What I would do is use a Singleton in which I can store the Data
class DataManager:NSObject
{
static let instance = DataManager()
override private init(){}
var items:[ApiItem] = []
}
Then in your first method I would do this:
func getLatest(pageNumber: Int){
let urlRequest = URL(string: baseUrl + latestUrl + String(pageNumber))
let requestedData = doRequest(url: urlRequest!, completion: { data -> items in
// We have the data from doRequest stored in data, but now what?!
DataManager.instance.items = items
})
}
This is how I usually go about this kind of situations. There may be better options though...

Swift 3: cant get image from Parse?

Ok, I have looked at questions like How do you access an object's fields from a Parse query result in Swift? but the answer is not working in Swift 3. With the following trying to get an image from the first PFObject in Parse I get the error:
Cannot convert value type NSData, NSError -> Void to expected
PFDataResultBlock ?
var query = PFQuery(className: PARSE_CLASS!)
query.order(byDescending: "createdAt")
query.findObjectsInBackground {
(objects, error) -> Void in
if error == nil {
//print(objects?.first?["testTxt"] as! NSString)
//print(objects?.first?["testImg"] as! PFFile)
let thumbnail = objects?.first?["testImg"] as! PFFile
thumbnail.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
//get image here
}
}
}
}
I have tried changing the type and everything. How can I store an image from Parse in recent Swift?
You can try this:
if let validObjects = objects {
for object in validObjects {
let thumbnail = object["testImg"] as? PFFile
thumbnail?.getDataInBackground (block: { (data, error) -> Void in
//read image here
}
}
}

In Swift, how do you check if pointer in Parse column is empty or not

Within my user object I added a column to add a users favorite team. The column is identified as favTeam and is a pointer to a teams class
Here is my code. I have populated my user with a favorite team however the logic is always showing that "favteam nil"
if let object = PFUser.currentUser()!["favTeam"] as? [PFObject]{
print("favteam not nil")
print(object)
let favTeam = PFUser.currentUser()!["favTeam"]
favTeamText.text = favTeam["Name"] as? String
if let favTeamImageView = favTeam["teamLogo"] as? PFFile {
favTeamImageView.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
self.teamLogo.image = UIImage(data: imageData)
}
}
}
}
}
else {
print("favteam nil")
}
I can accomplish this by using a PFUser.query() as follows...
func fetchFavoriteTeam() {
let userQuery: PFQuery = PFUser.query()!
userQuery.whereKey("username", equalTo: (currentUser?.username)!)
userQuery.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
var favTeam = users!
if error == nil {
if favTeam != nil {
favTeamContainer = favTeam.valueForKey("favTeam") as! PFObject
}
} else {
print(error)
}
})
}