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)
}
}
}
}
}
})
}
Related
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()
}
})
}
I openned an old ios project in Xcode with warnings about swift 4 updates.
During some fixing an error I could not find solution.
The error occours while looping jsonArray, passing values to variables...
let url=NSURL(string:"http://webserver.com/json")
let data = NSData(contentsOf: url! as URL)
do {
let jsonResult = try JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
let jsonArray = jsonResult.value(forKey: "person") as! NSArray
for json in jsonArray {
let id = json["id"] as? Int?
let name = json["name"] as? String
let age = json["age"] as? String
tableID.append(String(id!))
tableName.append(name!)
tableAge.append(age!)
tableView.reloadData()
}
} catch {
}
There are many don'ts in the code.
NSURL, NSData
NSArray, NSDictionary (which causes the error)
(NS)Data(contentsOf)
value(forKey:)
.mutableContainers
ignoring the error in the catch block
The actual native Swift syntax is
let url = URL(string:"http://webserver.com/json")!
let task = URLSession.shared.dataTask(with: url) { [unowned self] (data, response, error) in
if let error = error { print(error); return }
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!) as? [String:Any],
let jsonArray = jsonResult["person"] as? [[String:Any]] {
for json in jsonArray {
let id = json["id"] as! Int
let name = json["name"] as! String
let age = json["age"] as! String
self.tableID.append(String(id))
self.tableName.append(name)
self.tableAge.append(age)
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
task.resume()
There is one don't left: Don't use multiple arrays as data source.
I want to sort data with "id" key, how can I understand what is format string for NSPredicate format ? I have an 100 number post.
My code :
let objectIDs = posts.map{$0.id}
let predicate = NSPredicate(format: "self IN %#", objectIDs)
let sortByUserId = NSSortDescriptor(key: "id", ascending: true)
I have an error with this description:
can not parse "self IN %#" format string.
Code for Parsing JSON Data:
func postsFromJSONData(data : NSData, inContext context: NSManagedObjectContext) -> PostResult {
do{
let jsonObject : [[String:AnyObject]]
= try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [[String:AnyObject]]
for postJSON in jsonObject {
if let post = postFromJsonObject(postJSON, incontext : context) {
finalPost.append(post)
}
}
return .Sucsess(finalPost)
}
catch let error {
return .Failure(error)
}
}
fetch the main queue posts when the web service finishes:
func fetchRecentPost(completion completion: (PostResult) -> Void){
let request = NSURLRequest(URL: recentPostURL(["":""]))
let task = session.dataTaskWithRequest(request, completionHandler: {
(data, response, error) in
var result = self.processRecentPostRequest(data: data, error: error)
if case let .Sucsess(posts) = result {
let mainQueueContext = self.coreDataStack.mainQueueContext
mainQueueContext.performBlockAndWait(){
try! mainQueueContext.obtainPermanentIDsForObjects(posts)
}
let objectIDs = posts.map{$0.id}
let predicate = NSPredicate(format: "self IN %#", objectIDs)
let sortByUserId = NSSortDescriptor(key: "id", ascending: true)
do{
try self.coreDataStack.saveChanges()
let mainQueuePosts = try self.fetchMainQueuePosts(predicate: predicate, sortDiscriptors: [sortByUserId])
result = .Sucsess(mainQueuePosts)
}
catch let error {
result = .Failure(error)
}
}
completion(result)
})
Your predicte should be like this
let predicate = NSPredicate(format: "id IN %#", objectIDs)
let sortByUserId = NSSortDescriptor(key: "id", ascending: true)
Note : It is either self.id IN %# or id IN %#.
I've updated Xcode from 7 to 8 and Swift from 2.3 to 3.
I'm getting this error at let names = candidate["CandidateName"]!:
type nsfastenumerationiterator.element aka any has no subscript members
let url = URL(string: "https://website.com")
let data = try? Data(contentsOf: url!)
var tmpValues = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
tmpValues = tmpValues.reversed() as NSArray
reloadInputViews()
for candidate in tmpValues {
if ((candidate as? NSDictionary) != nil) {
let names = candidate["CandidateName"]!
//self.values.append(candidate["CandidateName"])
self.values.append(name!)
print(name)
}
}
I think your for in loop should like this. This is work for me. But be sure var tmpValues.
for candidate in (tmpValues as? [[String:Any]])! {
if ((candidate as? NSDictionary) != nil) {
let names = candidate["CandidateName"]! as? String
//self.values.append(candidate["CandidateName"])
self.values.append(name!)
print(name)
}
}
I've been trying to find out what causes memory leaks, but in Instruments, I am being told that the memory leak happens at seriesDownloadingQueue.addOperation(downloadOperation) and in the class that calls the method getSeries(), which starts the updating process.
I'm completely new to asynchronous programming and memory leaks. I've read some posts on stack overflow about finding and fixing the leaks. I've also read an article from http://www.raywenderlich.com on how to use Instruments. This app is a database preloader. It downloads and processes information. The .sqlite file will be used in a mobile app.
Below is the code which allegedly causes the memory leak. If you need more information, I'll provide it.
import Foundation
import CoreData
class SerieFetcher: NSObject{
dynamic var didGetSeries: Bool = false
static var doneSeries: Int = 0
func getSeries(){
var seriesDownloadingQueue: NSOperationQueue{
let val = NSOperationQueue()
val.maxConcurrentOperationCount = 32
val.name = "Serie Downloading & Processing Queue"
return val
}
var defaultSessionConfiguration:NSURLSessionConfiguration{
let val = NSURLSessionConfiguration.defaultSessionConfiguration()
val.HTTPMaximumConnectionsPerHost = 20
return val
}
let defaultSession: NSURLSession = NSURLSession(configuration: defaultSessionConfiguration,delegate: nil, delegateQueue: seriesDownloadingQueue)
if let countries = fetchCountries(){
for country in countries{
if let url = NSURL(string:(BASE_URL + "series/"+CAT_STAMPS+"producer/\(country.0)")){
let downloadOperation = downloadSeriesOperation(downloadURL: url, countryObjectID: country.1, countryCount: countries.count, defaultSession: defaultSession , completionHandler: { [weak self](didGetSeries) in
if(didGetSeries == true){
self!.didGetSeries = didGetSeries
print("Finished Downloading Series")
}
})
downloadOperation.completionBlock = nil
seriesDownloadingQueue.addOperation(downloadOperation)
}
}
}
}
func fetchCountries() -> [Int: NSManagedObjectID]?{
let fetchRequest = NSFetchRequest(entityName: "Country")
fetchRequest.resultType = .DictionaryResultType
let objectIDDesc = NSExpressionDescription()
objectIDDesc.name = "objectID"
objectIDDesc.expression = NSExpression.expressionForEvaluatedObject()
objectIDDesc.expressionResultType = .ObjectIDAttributeType
fetchRequest.propertiesToFetch = ["countryID",objectIDDesc]
fetchRequest.returnsDistinctResults = true
do{
let results = try managedContext.executeFetchRequest(fetchRequest) as! [NSDictionary]
var countryIDs: [Int: NSManagedObjectID] = [:]
for result in results{
let countryID: Int = result.valueForKey("countryID") as! Int
let objectID: NSManagedObjectID = result.valueForKey("objectID") as! NSManagedObjectID
countryIDs.updateValue(objectID, forKey: countryID)
}
return countryIDs
}catch let error as NSError{
print(error.localizedDescription)
}
return nil
}
}
class downloadSeriesOperation: NSOperation{
let countryObjectID:NSManagedObjectID
let downloadURL:NSURL
let countryCount:Int
let defaultSession:NSURLSession
let completionHandler: (didGetSeries: Bool) -> Void
init(downloadURL:NSURL, countryObjectID: NSManagedObjectID,countryCount: Int, defaultSession:NSURLSession, completionHandler: (didGetSeries:Bool) -> Void){
self.downloadURL = downloadURL
self.countryObjectID = countryObjectID
self.countryCount = countryCount
self.defaultSession = defaultSession
self.completionHandler = completionHandler
}
override func main() {
let dataTask = defaultSession.dataTaskWithURL(downloadURL, completionHandler: { (data, response, error) in
let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.persistentStoreCoordinator = managedContext.persistentStoreCoordinator
privateMOC.undoManager = nil
var parsedData: NSArray?
do{
parsedData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as? NSArray
}catch let error as NSError{
print(error.localizedDescription)
}
for val in parsedData!{
if let serieID = Int(val[0] as! NSString as String){
if let serieName = val[1] as? NSString as? String{
if serieID == 0{
continue
}
let serie = NSEntityDescription.insertNewObjectForEntityForName("Serie", inManagedObjectContext: privateMOC) as! Serie
serie.country = privateMOC.objectWithID(self.countryObjectID) as? Country
serie.serieID = serieID
serie.serieName = serieName
}
}
}
privateMOC.performBlock({
do{
try privateMOC.save()
privateMOC.reset()
}catch let error as NSError{
print(error.localizedDescription)
}
})
SerieFetcher.doneSeries += 1
print(self.countryCount,"/",SerieFetcher.doneSeries)
if(SerieFetcher.doneSeries == self.countryCount){
self.completionHandler(didGetSeries: true)
}
})
dataTask.resume() //Start the Download
}
}