Implement MCOHTMLRendererIMAPDelegate in MailCore2 using Swift - ios

Recently I've been trying to use MailCore2 inside my react-native app to read mails, so I made a RCTBridge in Swift for it, and I want to return a simple html string of fetched messages... I have successfully fetched messages of type [MCOIMAPMessage] and now I want to map over this array to convert it to html string with the following code
let msgs = (ret.value(forKey: "messages") as! [MCOIMAPMessage]).map{
[
"html": $0.htmlRendering(withFolder: folder as String,
delegate: MCOHTMLRendererIMAPDelegate()) as NSString,
] as NSDictionary
}
Obviously it gives an error, can somebody please tell me the right way to do it...? Or at least tell me how to implement a MCOHTMLRendererIMAPDelegate

Related

Swift iOS check if a file has been downloaded from json

I have an app that displays and plays a list of podcasts that is fetched from a json file, I would like to add a download feature but to do this I would like to only show a download icon if the podcast has not been downloaded already, is there a way that I can save something like the id element as well as the podcast title so I could then check to see if its been downloaded and saved on the phone already? Or is there an easier way? Obviously I would like to do this before the list is shown.
You can use UserDefaults for that.
Here's an example on how to read an array from UserDefaults
// Retrieves an array of strings from disk
func getDowloadedPodcasts() -> [String] {
UserDefaults.standard.array(forKey: "downloadedPodcasts") as? [String] ?? []
}
And here's an example on how to append a new value to an array on UserDefaults
func addDownloadedPodcast(podcastId: String) {
let downloadedPodcasts = getDowloadedPodcasts()
downloadedPodcasts.append(podcastId)
UserDefaults.standard.setValue(podcastId, forKey: "downloadedPodcasts")
}
Note that this functions alone won't solve your problem nor are the best solution of your problem, they are here jsut to show how easy it can be to work with UserDefaults and to read/write from non-volatile memory

JSON text did not start with array or object

Working with an iOS app managing data on a Parse-Server (/Heroku).
I have the following issue when trying to save data.
Here is the code for the function where the problem happens:
func saveDataBlockOnline(_ dico: [String:String]) {
let psvClassName = "Goodies",
dataUnit=PFObject(className: psvClassName,
dictionary: dico)
dataUnit.saveInBackground {
(succeeded:Bool, error:Error?) in
if succeeded {
// Do something useful.
} else {print("\(#function) Error:\(error ?? "" as! Error)")}
}
}
Here is the error I get:
saveDataBlockOnline Error:Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
I guess I am getting some JSON answer that I don't use properly. So how should I modify the code?
There are other posts on the subject, but nothing that I found with a real solution.
A few more details may be useful:
The data saving on the server itself was working. But things started to go wrong when I added some cloud code, namely a Parse.Cloud.beforeSave to have a better control on how things are happening.
The data you want to parse in not in correct format according to error message. Check your dictionary and Object(dataUnit) format

Kinvey 3.3.5 SDK Query By Ids

I am currently going through the processes of migrating swift 2.3 to 3 using the most updated Kinvey SDK (version 3.3.5). They have done a ton of updates since the 1x versions. My question is has anyone successfully been able to query on the PersistableKeyID field and pull multiple objects?
I use to be able to use the "loadObjects" function which would take an array of strings as an argument. This function has since been depreciated and replaced with find(byId). See below:
dataStore.find(byId: "only takes one") { uClass, error in
if let uClass = uClass {
//succeed
print("UClass: \(uClass)")
} else {
//fail
}
The issue is, it will only take a single string as an argument. I have attempted to use the query functionality, but I cannot get it to take the "_id" field as a parameter. Using the following code:
//Just statically creating the sectionID array for now. This will dynamically be created
testIDs = ["58668307206c11177e5ab0d4", "58668307206c11177e5ab0d4", "57ad00a505a2bb55632659c3"]
let sectionStore = DataStore<Section>.collection()
let sectionQuery = Query(format: "_id IN %#", testIDs)
sectionStore.find(sectionQuery) {sectionResult, error in
if let sectionResult = sectionResult {
self.sectionsTest = sectionResult
self.sectionCollectionView.reloadData()
} else{
//Error
}
}
I receive the error:
'Invalid property name', reason: 'Property '_id' not found in object of type 'Section'
Anyone have an idea on how to perform this now that "loadObjects" has been depreciated? There is no delivered "find(byIds)" that I could find.
Jbone107,
I was able to get results with this, let me know if the below works for you.
let id:[String] = ["5855026650a816ec29012908","5855024a21400c5b492bea20"]
let query = Query(format: "_id IN %#", id)
dataStore.find(query) { data, error in
if let data = data {
//succeed
print(“Data: \(data)")
} else {
//fail
print("fetching failed")
}
}
Thanks,
Pranav,
Kinvey
Answered: Per the Data Store Guide for iOS, by default the ".collection()" is of type "cache". The "Cache" type will store data locally. This must be why "Realm" is now included with the version 3x SDK.
I updated my DataStore collection to:
let sectionStore = DataStore<Section>.collection(.network)
I added ".network" to force the query to pull from the backend rather than the cache file. This actually identified "_id" as a property and the query worked successfully. For some reason the "cache" file isn't storing this as a property.
Additional SDK Question Answered
I was having an issue pulling NSNumber from the Kinvey backend. This ended up being a similar issue related to the "cache" query. I reviewed the Realm support site as a last resort effort to try and figure this out. I found that Realm doesn't actually support type "NSNumber".
Excerpt taken from: https://realm.io/docs/swift/latest/
Realm supports the following property types: Bool, Int8, Int16, Int32, Int64, Double, Float, String, NSDate, and NSData.
Unfortunately, Kinvey doesn't support "Int" types. As a work around, I have changed them to string and am just converting back to "Double" or another type after I pull the data. However, if I just use ".network" collection types, then NSNumber still works.
Thanks,
James

Failed to send custom object using WatchConnectivity (swift)

I was trying to pass my swift object from the iOS app to the Watch. However, I found it works for basic types like NSString, but my custom object type.
My custom object is able to cast to NSData
I've made my object implement NSObject and NSCoding, which works well. I can do following without problem:
let encodedChordProgression = NSKeyedArchiver.archivedDataWithRootObject(chordProgressions[1])
let decodedChordProgression = NSKeyedUnarchiver.unarchiveObjectWithData(encodedChordProgression) as! ChordProgression
NSLog("get decodedChordProgression = \(decodedChordProgression.description)")
WatchConnectivity code works for NSString
In iPhone:
try WatchSessionManager.sharedManager.updateApplicationContext(["data": "mystringishere"])
with Watch:
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.dataSourceChangedDelegates.forEach { $0.dataSourceDidUpdate(applicationContext["data"] as! NSString)}
}
works.
My custom object with WatchConnectivity Failed
However, when I switch the object to my own object, it failed by not calling the dataSourceChangedDelegates callback function. That is:
In iPhone:
let encodedChordProgression = NSKeyedArchiver.archivedDataWithRootObject(chordProgressions[1])
try WatchSessionManager.sharedManager.updateApplicationContext(["data": encodedChordProgression])
with Watch:
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.dataSourceChangedDelegates.forEach { $0.dataSourceDidUpdate(applicationContext["data"] as! NSData)}
}
and
func dataSourceDidUpdate(encodedChordProgression: NSData) {
let chordProgression = NSKeyedUnarchiver.unarchiveObjectWithData(encodedChordProgression) as! ChordProgression
NSLog("get something here: \(chordProgression.description)")
}
What I've tried & my problem
I've tried to read the system.log of both the iPhone app and Watch app, but I couldn't find any clue, which is the biggest problem I have now.
The full code is: here (checkout 7f2a72c6004f6580e2a38a2d7fd0ed2cef8a2b2e)
NSKeyedArchiver/NSKeyedUnarchiver won't work in this way unfortunately. This is because even though you may share class files between your watchkit and iOS targets, they are essentially different classes to the compiler because they are compiled for different architectures.
What I have done to get around this issue myself (because I initially tried to do the same thing) is serialize my custom objects to a json dictionary (or json NSData if you like) and send that. Here is a github project I have made that automatically serializes your swift objects to json for you (specifically with this use case in mind).
I tried with "NSKeyedArchiver/NSKeyedUnarchiver" and this is working perfectly.
no need to go for serialization and all.
your dictionary should have same type of data and Archiver is doing it very well.

parsing json in swift

I'm trying to read the Linkedin response in swift.
My object is something like this ["positions":["values":["data1","data2","data3"]]]
if let positions: NSDictionary = info["positions"] as NSDictionary!{
if let positionsInfo: [NSDictionary] = positions["values"] as? [NSDictionary]{
for position : NSDictionary! in positionsInfo {
dosomething(position, person:usr)
}
}
}
If I do a StepOver line by line it works correctly. But if I run it i'll get a EXC_BAD_ADDRESS(code=1,address=0x7966b04) I enabled Zombie objects and ran it on Instruments. I'm pretty sure this is the code which is causing the problem. But not sure what is wrong with it.
The moment you used ! you opened yourself up for crashes if there were any problem. You must use as? to make sure that the data is actually what you think it is.
There are many blog posts out there on how to safely parse JSON into Swift data structures. It's now almost a rite of passage for Swift bloggers.
http://robots.thoughtbot.com/efficient-json-in-swift-with-functional-concepts-and-generics
http://chris.eidhof.nl/posts/json-parsing-in-swift.html
https://github.com/owensd/json-swift
https://github.com/lingoer/SwiftyJSON
Of course the many packages: https://github.com/search?q=%5Bswift%5D+json
http://robnapier.net/functional-wish-fulfillment - My own version on top of all the others

Resources