func retrieveMessages() {
var query:PFQuery = PFQuery(className: "Message")
//Call findobjectsinbackground
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
self.messagesArray = [String]()
for messageObject in objects { <<<<<<<<<<<<<<<<< error
let messageText:String? = (messageObject as PFObject)["Text"] as? String
if messageText != nil {
self.messagesArray.append(messageText!)
}
}
self.messageTableView.reloadData()
}
}
From this code an error occurs saying: [AnyObject]? does not have a member named 'Generator'. Is there a way how to correct this?
Your objects array is declared as an Optional : objects:[AnyObject]?
So you need to unwrap it before looping over it:
for messageObject in objects! {
// do stuff
}
And since objects can be nil, better do this:
if let myObjects = objects {
for messageObject in myObjects {
// do stuff
}
}
That's because it is an optional array. Simply wrap it around if let and you'll be fine.
In playground:
func retrieveMessages(objects:[AnyObject]?) {
var messagesArray = [String]()
if let objs = objects {
for messageObject in objs {
let messageText:String? = "test"
if messageText != nil {
messagesArray.append(messageText!)
}
}
}
}
In your case, the complete code would be:
func retrieveMessages() {
var query:PFQuery = PFQuery(className: "Message")
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
self.messagesArray = [String]()
if let objs = objects {
for messageObject in objs {
let messageText:String? = (messageObject as PFObject)["Text"] as? String
if messageText != nil {
self.messagesArray.append(messageText!)
}
}
}
self.messageTableView.reloadData()
}
}
Since your objects Array is of [AnyObject]?, before using them you need to do below step.
if let myObjects = objects as? [PFObject] {
//Do the things...
}
[AnyObject]? it´s an optional array.
You must unwrap it before using it.
if let objects = objects
{
for messageObject in objects
{
....
}
}
Related
I'm using socket.io Swift Library. With the following line of code,
socket.on("info") { (dataArray, socketAck) -> Void in
let user = dataArray[0] as? User
print(user._id)
}
dataArray[0] is a valid object but user appears to be nil after casting.
Since dataArray[0] returns as an AnyObject,
how can i cast AnyObject to User Object?. Or somehow manage to do what i want with a different approach?
Since after this line
let user = dataArray[0] as? User
you have a nil value inside user it means that you don't have a User value at the first position of dataArray.
Since dataArray comes from a server (as I guess) it probably contains a serialized version of User.
Now we really need to know what really dataArray[0] is. However...
if dataArray[0] contains NSData
In this case try this
let json = JSON(dataArray[0] as! NSData)
let user = User(json:json)
You need to create a constructor that accept AnyObject and read data in it.
I guess in this case dataArray[0] is an JSON Object.
class User {
init(data: [String: AnyObject]) {
username = data["username"] as? String ?? ""
}
}
This is how i manage mine:
// Structure used as parameter
struct InfoStruct {
var nome: String = ""
var sobrenome:String = ""
var nascimentoTimestamp: NSNumber = 0
init() {
}
// Struct to AnyObject
func toAnyObject() -> Any {
var dic = [String:AnyObject?]()
if (nome != "") { dic["nome"] = nome as AnyObject }
if (sobrenome != "") { dic["sobrenome"] = sobrenome as AnyObject }
if (nascimentoTimestamp != 0) { dic["nascimentoTimestamp"] = nascimentoTimestamp as AnyObject }
return dic
}
// AnyObject to Struct
func fromAnyObject(dic:[String:AnyObject]) -> InfoStruct {
var retorno = InfoStruct()
if (dic["nome"] != nil) { retorno.nome = dic["nome"] as? String ?? "" }
if (dic["sobrenome"] != nil) { retorno.sobrenome = dic["sobrenome"] as? String ?? "" }
if (dic["nascimentoTimestamp"] != nil) { retorno.nascimentoTimestamp = dic["nascimentoTimestamp"] as? NSNumber ?? 0 }
return retorno
} }
// User class
class Usuario: NSObject {
var key: String
var admin: Bool
var info: InfoStruct // Struct parameter
init(_ key: String?) {
self.key = key ?? ""
admin = false
info = InfoStruct() // Initializing struct
}
// From Class to AnyObject
func toAnyObject() -> Any {
var dic = [String:AnyObject?]()
if (key != "") { dic["key"] = key as AnyObject }
if (admin != false) { dic["admin"] = admin as AnyObject }
dic["info"] = info.toAnyObject() as AnyObject // Struct
return dic
}
// From AnyObject to Class
func fromAnyObject(dic:[String:AnyObject]) -> Usuario {
let retorno = Usuario(dic["key"] as? String)
if (dic["key"] != nil) { retorno.key = dic["key"] as? String ?? "" }
if (dic["admin"] != nil) { retorno.admin = dic["admin"] as? Bool ?? false }
if (dic["info"] != nil) { retorno.info = InfoStruct.init().fromAnyObject(dic: dic["info"] as! [String : AnyObject]) } // Struct
return retorno
} }
// Using
let dao = FirebaseDAO.init(_type: FirebaseDAOType.firebaseDAOTypeUser)
dao.loadValue(key: uid) { (error, values:[String : AnyObject]) in
if error == nil {
let user = Usuario(values["key"] as? String).fromAnyObject(dic: values)
}
}
I hope it helps!
I can't understand what is wrong with this function:
var arrayStatusUserTable:[String] = [String]()
var statusText:String = String()
func retrieveStatusInTable(name: String) -> String {
var statusFinal:String = String()
var query:PFQuery = PFQuery(className: "Status")
query.whereKey("NameCreator", equalTo: name)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
for phrase in objects! {
let phraseTakenParse:String? = (phrase as! PFObject)["Status"] as? String
if phraseTakenParse != nil {
self.arrayStatusUserTable.append(phraseTakenParse!)
}
}
// Take the last status
if var frase = self.arrayStatusUserTable.last {
var lastFraseStatus:String = frase //self.arrayStatusUtente.last!
self.statusText = lastFraseStatus
statusFinale = lastFraseStatus
return statusFinale
}
}
}
This one return the error: 'String' is not convertible to 'Void'! I just wanna return the last object from the array filled from Parse! Thanks for helping me!
return statusFinale written in blocks, so retrieveStatusInTable function return Void.
When you use asynchronous method, set function return type "Void" and tell result with blocks (completionHandler).
Sample Code:
func retrieveStatusInTable(name: String, completionHandler:((statusFinale: String) -> Void)) {
// .....
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
// ........
statusFinale = lastFraseStatus
completionHandler(statusFinale: statusFinal)
}
}
Usage:
retrieveStatusInTable("Sample", { (statusFinale) -> Void in
println(statusFinale)
})
func getParse (className:String,key:String,dataName:AnyObject) -> (String)
{
var result = String()
var query = PFQuery(className: className)
query.whereKey(key, equalTo: dataName)
query.findObjectsInBackgroundWithBlock{
(objects, error) -> Void in
if error == nil {
println("Found")
if let objects = objects as? [PFObject] {
for object in objects {
result = object[key] as! String
}
}
} else {
println("Error \(error) \(error!.userInfo!)")
}
}
return result
}
This is my function that can getting data from my class in parse database. I want to return that data in String but it returned nothing when I try to printed it.
Thank you for every comments.
You are using an asynchronous call. You need to use findObjects(), but this will stay on the main thread. Why do you need to return a string? You could set a variable from within the completion block that could update a label on your view or something like that.
Edit: Since you are trying to set a label, you don't need to return the string, you should just set the label from within your completion block. This would modify you're given code as follows:
func getParse (className:String,key:String,dataName:AnyObject)
{
var result = String()
var query = PFQuery(className: className)
query.whereKey(key, equalTo: dataName)
query.findObjectsInBackgroundWithBlock{
(objects, error) -> Void in
if error == nil {
println("Found")
if let objects = objects as? [PFObject] {
for object in objects {
// result = object[key] as! String
self.textLabel.text = result // NEW CODE HERE
}
}
} else {
println("Error \(error) \(error!.userInfo!)")
}
}
}
How do I check if core data is empty using Swift. I tried this method:
var people = [NSManagedObject]()
if people == nil {
}
but this results in this error:
“binary operator '==' cannot be applied to operands of type [NSManagedObject] and nil”
Swift 3 solution:
var isEmpty: Bool {
do {
let request = NSFetchRequest(entityName: YOUR_ENTITY)
let count = try context.count(for: request)
return count == 0
} catch {
return true
}
}
Based on Dejan Skledar's answer I got rid of some compiler warnings and adopted it to Swift 2.0.
func entityIsEmpty(entity: String) -> Bool
{
let context = NSManagedObjectContext()
let request = NSFetchRequest(entityName: entity)
var results : NSArray?
do {
results = try context.executeFetchRequest(request) as! [NSManagedObject]
return results.count == 0
} catch let error as NSError {
// failure
print("Error: \(error.debugDescription)")
return true
}
}
However, I am not sure if the if let res=results clause along with its else clause ist required or not.
To check if the Core Database is empty you have to make a NSFetchRequest on the entity you want to check, and check if the results of the request are empty.
You can check it with this function:
func entityIsEmpty(entity: String) -> Bool
{
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context = NSManagedObjectContext()
var request = NSFetchRequest(entityName: entity)
var error = NSErrorPointer()
var results:NSArray? = self.context.executeFetchRequest(request, error: error)
if let res = results
{
if res.count == 0
{
return true
}
else
{
return false
}
}
else
{
println("Error: \(error.debugDescription)")
return true
}
}
Or simplier and shorter solution: (using .countForFetchRequest)
func entityIsEmpty(entity: String) -> Bool
{
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context = NSManagedObjectContext()
var request = NSFetchRequest(entityName: entity)
var error = NSErrorPointer()
var results:NSArray? = self.context.executeFetchRequest(request, error: error)
var count = context.countForFetchRequest(request, error: error)
if error != nil
{
println("Error: \(error.debugDescription)")
return true
}
else
{
if count == 0
{
return true
}
else
{
return false
}
}
}
SwiftUI Solution
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \MyObject.created, ascending: true)],
animation: .default)
private var myobjects: FetchedResults<MyObject>
var body: some View {
if self.myobjects.isEmpty{
Text("There are no objects in the current database.")
}
else{
// whatever
}
}
}
The problem I'm having on this request is the first function syncRequest always returns nil since the function exits before the (reply, error) comes back to fill out my return dictionary.
Is there a way for it to wait for the callback to return before returning out of my closure?
public typealias KKWatchSyncResponse = Dictionary<String, AnyObject>
func syncRequest() -> KKWatchSyncResponse? {
var syncResponseDict : KKWatchSyncResponse?
createRequest(KKWatchRequest.Sync, parameter: nil) { reply, error in
if reply == nil || error != nil {
return
} else {
syncResponseDict = KKWatchSyncResponse()
}
if let songInfo = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["songInfo"] as NSData) as NSDictionary? {
syncResponseDict!["songInfo"] = songInfo
}
if let albumArtImage = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["albumArt"] as NSData) as? UIImage {
syncResponseDict!["albumArtImage"] = albumArtImage
}
if let isPlaying = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["isPlaying"] as NSData) as? Bool {
syncResponseDict!["isPlaying"] = isPlaying
}
}()
return syncResponseDict
}
func createRequest(request:KKWatchRequest, parameter: KKWatchAPIRequestParameter?, callback:KKWatchAPICallback) -> KKWatchAPIParentRequest {
var requestDict : Dictionary<String, AnyObject> = [KKBOXWatchAppRequestType : request.rawValue]
if parameter != nil {
requestDict += parameter! //Combine 2 dictionaries
}
return { WKInterfaceController.openParentApplication(requestDict){ reply, error in
callback(reply, error)
}
}
}
Your help us much appreciated!
Could you have syncRequest() take a closure that gets called with the results when ready? Change the definition to something like:
func syncRequest(callback:(KKWatchSyncResponse?)->Void) { ... }
Then at the end of your createRequest() call, you could call the callback on syncResponseDict, since now it's been populated with your data... callback(syncResponseDict).
EDIT: Here's the solution I had in mind.
func syncRequest(callback:(KKWatchSyncResponse?)->Void) {
createRequest(KKWatchRequest.Sync, parameter: nil) { reply, error in
if reply == nil || error != nil {
callback(nil)
} else {
var syncResponseDict : KKWatchSyncResponse? = KKWatchSyncResponse()
if let songInfo = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["songInfo"] as NSData) as NSDictionary? {
syncResponseDict!["songInfo"] = songInfo
}
if let albumArtImage = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["albumArt"] as NSData) as? UIImage {
syncResponseDict!["albumArtImage"] = albumArtImage
}
if let isPlaying = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["isPlaying"] as NSData) as? Bool {
syncResponseDict!["isPlaying"] = isPlaying
}
callback(syncResponseDict)
}
}()
}
It is straight forward to implement a locking variable. This is most helpful for unit tests that do some async network loading.
func waitingFunction()
{
//set a lock during your async function
var locked = true
RunSome.asyncFunction() { () -> Void in
//after your sync function remove the lock
locked = false
})
//wait for the async method to complete before advancing
while(locked){wait()}
//move on from the lock
doMoreStuff()
}
func wait()
{
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: 1))
}