Parse error when trying to upload PFObject - parse-platform

I'm trying to make a messaging app in Parse, but I get this error when trying to upload a PFObject.
The error says:
2014-11-22 14:43:21.154 Parse demo[688:27950] Warning: A long-running operation is being executed on the main thread.
Break on warnBlockingOperationOnMainThread() to debug.
and my code is for the sender-button is:
#IBAction func sendButton(sender: AnyObject) {
var message = PFObject(className:"message")
message["message"] = send.text
message.save()
where send.text is just a text-box.
Any recommendations or ways to proceed would be highly appreciated.

Try this instead. then you save in a background blok
#IBAction func sendButton(sender: AnyObject) {
var message = PFObject(className:"message")
message["message"] = send.text
message.saveInBackgroundWithBlock {
(succeeded: Bool!, error: NSError!) -> Void in
if (error != nil) {
println("Save : \(error)")
}
else{
println("Success! with save")
}
}
}

This is not exactly an error, but more a hint, that it'll block the app because you are making a synchronous save call. Use one of the saveInBackground* methods instead and the save will take place asynchronously on a background job.

Related

How do I read a text-file's content from it's shared Dropbox link in Swift 4.2 (without downloading)?

I'm having a hard time figuring out how to output a simple text-file's content from it's shared Dropbox link (without downloading) through Swift 4.2.
For Example:
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=0")!
// the dropbox link above is a shared link so anyone can view it
do {
let content = try String(contentsOf: url)
print("File Content: \(content)")
} catch let error as NSError {
print("\(error)")
}
When I run this code I get this error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “test.txt” couldn’t be opened because there is no such file."(there's more to the error but it's quite big)
Can anyone help me out please? Thanks.
There's more to the error but it's quite big
Do not strip error messages. If you don't know to fix this issue, you probably don't know what to strip to keep it valuable.
How to fix your problem
Select target
Switch to Signing & Capabilities tab
App Sandbox - Network - enable Outgoing Connections (Client)
Change the URL (dl=0) to (dl=1)
0 = display web page with a preview and download link
1 = do not display any web page, just serve the file
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=1")!
// Change dl=0 to dl=1 ^
do {
let content = try String(contentsOf: url)
print("File Content: \(content)")
} catch let error as NSError {
print("\(error)")
}
Run again and you'll get:
File Content:
This is a test. If you can read this, you have passed! :)
Do not use String(contentsOf: url), because it's not async and it will block the main thread (UI).
Asynchronous example - imagine you have a view controller with one text field (label) and you'd like to display the file content there:
import Cocoa
class ViewController: NSViewController {
#IBOutlet var textField: NSTextField!
override func viewWillAppear() {
super.viewWillAppear()
textField.stringValue = "Loading ..."
loadRemoteFile()
}
func loadRemoteFile() {
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=1")!
let task = URLSession.shared.dataTask(with: url) { data, _, error in
// Following code is not called on the main thread. If we'd like to
// modify UI elements, we have to dispatch our code on the main thread.
// Hence the DispatchQueue.main.async {}.
if let error = error {
print("Failed with error: \(error)")
DispatchQueue.main.async { self.textField.stringValue = "Failed" }
return
}
guard let data = data,
let content = String(data: data, encoding: .utf8) else {
print("Failed to decode data as an UTF-8 string")
DispatchQueue.main.async { self.textField.stringValue = "Failed" }
return
}
print("Content: \(content)")
DispatchQueue.main.async { self.textField.stringValue = content }
}
// At this point, we have a task which will download the file, but the task
// is not running. Every task is initially suspended.
task.resume() // Start the background task
// At this point, your program normally continues, because the download
// is executed in the background (not on the main thread).
}
}

Xcode Swift macOS, Terminal App not doing NSURLSession

Trying to poll the content of a website, no matter if JSON or REST API, I cannot seem to make it work. The same code works for iOS App, but will not get the content when being used within a Swift macOS Terminal application. What's the main reason?
The project does not have an Info.plist file.
Here's a code example that works within an iOS application, but not within the macOS Terminal application. I call the function with a simple jsonParser(), which initiates the NSURLSession and prints the JSON when it's arrived.
enum JSONError: String, ErrorType {
case NoData = "ERROR: no data"
case ConversionFailed = "ERROR: conversion from JSON failed"
}
func jsonParser() {
let urlPath = "https://api.coindesk.com/v1/bpi/currentprice.json"
guard let endpoint = NSURL(string: urlPath) else {
print("Error creating endpoint")
return
}
let request = NSMutableURLRequest(URL:endpoint)
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
do {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary else {
throw JSONError.ConversionFailed
}
print(json)
} catch let error as JSONError {
print(error.rawValue)
} catch let error as NSError {
print(error.debugDescription)
}
}.resume()
}
I was able to solve my problem by adding
dispatch_main()
at the end of my main program code. Listed above was the function to request the web data. Thanks to Martin and Eric for pointing it out.

This application is modifying the autolayout engine from a background thread swift2.0

I am using this simple code to extract some plain text from a website.
#IBAction func askWeather(sender: AnyObject) {
let url = NSURL(string: "http://www.weather-forecast.com/locations/" + userField.text! + "/forecasts/latest")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
if let urlContent = data{
let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)
let wArray = webContent?.componentsSeparatedByString("Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
let wCont = wArray![1].componentsSeparatedByString("</span>")
self.weatherResult.text = wCont[0]
}
else{
print("Sorry could not get weather information")
}
}
task.resume()
}
#IBOutlet var weatherResult: UILabel!
#IBOutlet var userField: UITextField!
And after i press the button to fetch the information nothing happens for several seconds(like 10-20) and then i get the correct result however i get this message in xcode:
This application is modifying the autolayout engine from a background
thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.
I tried reading some posts on others having this problem but they were using threads like async etc. to run their code. Im not really sure what the problem is in my case.
Thank you!
I'm guessing that self.weatherResult.text = wCont[0] is modifying something like a UILabel or similar, in which case you're trying to change part of your user interface from a background thread – a big no-no.
Try code like this instead:
dispatch_async(dispatch_get_main_queue()) { [unowned self] in
self.weatherResult.text = wCont[0]
}
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
There's your asynchronous thread. Right there. dataTaskWithURL runs in the background and will eventually call the callback function that you passed in. And that is done in the background.

Passing Dictionary to Watch

I'm trying to pass data from iPhone -> Watch via Watch Connectivity using background transfer via Application Context method.
iPhone TableViewController
private func configureWCSession() {
session?.delegate = self;
session?.activateSession()
print("Configured WC Session")
}
func getParsePassData () {
let gmtTime = NSDate()
// Query Parse
let query = PFQuery(className: "data")
query.whereKey("dateGame", greaterThanOrEqualTo: gmtTime)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objectsFromParse = objects as? [PFObject]{
for MatchupObject in objectsFromParse
{
let matchupDict = ["matchupSaved" : MatchupObject]
do {
try self.session?.updateApplicationContext(matchupDict)
print("getParsePassData iPhone")
} catch {
print("error")
}
}
}
}
}
}
I'm getting error twice printed in the log (I have two matchups in Parse so maybe it knows there's two objects and thats why its throwing two errors too?):
Configured WC Session
error
error
So I haven't even gotten to the point where I can print it in the Watch app to see if the matchups passed correctly.
Watch InterfaceController:
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
let matchupWatch = applicationContext["matchupSaved"] as? String
print("Matchups: %#", matchupWatch)
}
Any ideas? Will post any extra code that you need. Thanks!
EDIT 1:
Per EridB answer, I tried adding encoding into getParsePassData
func getParsePassData () {
let gmtTime = NSDate()
// Query Parse
let query = PFQuery(className: "data")
query.whereKey("dateGame", greaterThanOrEqualTo: gmtTime)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objectsFromParse = objects as? [PFObject]{
for MatchupObject in objectsFromParse
{
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
let matchupDict = ["matchupSaved" : data]
do {
try self.session?.updateApplicationContext(matchupDict)
print("getParsePassData iPhone")
} catch {
print("error")
}
}
}
}
}
}
But get this in the log:
-[PFObject encodeWithCoder:]: unrecognized selector sent to instance 0x7fbe80d43f30
*** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
EDIT 2:
Per EridB answer, I also tried just pasting the function into my code:
func sendObjectToWatch(object: NSObject) {
//Archiving
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
//Putting it in the dictionary
let matchupDict = ["matchupSaved" : data]
//Send the matchupDict via WCSession
self.session?.updateApplicationContext(matchupDict)
}
But get this error on the first line of the function:
"Use of unresolved identifer MatchupObject"
I'm sure I must not be understanding how to use EridB's answer correctly.
EDIT 3:
NSCoder methods:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
//super.init(coder: aDecoder)
configureWCSession()
// Configure the PFQueryTableView
self.parseClassName = "data"
self.textKey = "matchup"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
Error
You are getting that error, because you are putting a NSObject (MatchupObject) which does not conform to NSCoding inside the dictionary that you are going to pass.
From Apple Docs
For most types of transfers, you provide an NSDictionary object with
the data you want to send. The keys and values of your dictionary must
all be property list types, because the data must be serialized and
sent wirelessly. (If you need to include types that are not property
list types, package them in an NSData object or write them to a file
before sending them.) In addition, the dictionaries you send should be
compact and contain only the data you really need. Keeping your
dictionaries small ensures that they are transmitted quickly and do
not consume too much power on both devices.
Details
You need to archive your NSObject's to NSData and then put it in the NSDictionary. If you archive a NSObject which does not conform to NSCoding, the NSData will be nil.
This example greatly shows how to conform a NSObject to NSCoding, and if you implement these things then you just follow the code below:
//Send the dictionary to the watch
func sendObjectToWatch(object: NSObject) {
//Archiving
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
//Putting it in the dictionary
let matchupDict = ["matchupSaved" : data]
//Send the matchupDict via WCSession
self.session?.updateApplicationContext(matchupDict)
}
//When receiving object from the other side unarchive it and get the object back
func objectFromData(dictionary: NSDictionary) -> MatchupObject {
//Load the archived object from received dictionary
let data = dictionary["matchupSaved"]
//Deserialize data to MatchupObject
let matchUpObject = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! MatchupObject
return matchUpObject
}
Since you are using Parse, modifying an object maybe cannot be done (I haven't used Parse in a while, so IDK for sure), but from their forum I found this question: https://parse.com/questions/is-there-a-way-to-serialize-a-parse-object-to-a-plain-string-or-a-json-string which can help you solve this problem easier than it looks above :)

Opentok sending signal ios

I got a problem with OpenTok, I got a session of OTSession and I want to call the method signalWithType so I can send a chat message.
In the start I have
var session : OTSession?
And then in my method where I want to send chat message from textField I get the error 'Could not find memember 'signalWithType'
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
let message = sendMessageField.text
sendMessageField.text = ""
var type = ""
var maybeError : OTError?
session?.signalWithType(type, string: message, connection: nil, error: maybeError)
if let error = maybeError {
println(error)
} else {
println("besked blev sendt")
}
return false
}
I can't find out why it says it as I pretty sure I got the right types and that.
I have not have other problems with calling methods from session..

Resources