convert string unicode 8 swift - swift

i was a nsdata from json
when i put in string i get "#1495;#1493;#1507; #1492;#1510;#1493;#1511; +& Before each tag
i need it in Hebrew
the code is
let json_url = NSURL(string: "http://itaypincas7.ipage.com/WigiTech-DB/createJSON.php")
let jsonData = NSData(contentsOfURL: json_url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
for (_, subJson) in json {
let id = Int(subJson["id"] as! String)
let name: String = subJson["name"] as! String
let area: String = subJson["area"] as! String
let latitude = CLLocationDegrees(CGFloat(Float(subJson["latitude"] as! String)!))
let longitude = CLLocationDegrees(CGFloat(Float(subJson["longitude"] as! String)!))
let beachNew = BeachNew(id: id!, name: name, area: area, latitude: latitude, longitude: longitude)
beachesList.append(beachNew)
}

You can use NSAttributedString to replace the HTML entities. Here's an example for decoding the name variable.
let name: String = subJson["name"] as! String
let nameData = name.dataUsingEncoding(NSUTF8StringEncoding)!
let options: [String: AnyObject] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
]
let attributedName = try NSAttributedString(data: nameData, options: options, documentAttributes: nil)
let decodedName = attributedName.string
The value of decodedName will have all entities replaced with the Hebrew characters you're looking for.

Related

Not able to read data from Firebase realtime database

I have stored the comments under a post in firebase realtime database. The problem i have is that when i try to parse out the data from firebase i get an error that says Unexpectedly found nil while unwrapping an Optional value. So for example if i try to pront the data stored under degree, i get this nil error. But when i print "comments" instead of the "degree" i successfully fetch the data. My database structure looks like this.
func obeserveComments() {
// get auto-id of post
let commentKey = self.keyFound
let postRef = Database.database().reference().child("posts").child(commentKey)
var tempComments = [Comments]()
postRef.observe(.value, with: {(snapshot) in
if let dict = snapshot.value as? [String:Any] {
if let comments = dict["comments"] as? [String:Any] {
let degree = comments["reply degree"] as! String
// let name = comments["reply name"] as! String
// let text = comments["reply text"] as! String
// let university = comments["reply university"] as! String
// let photoURL = comments["reply url"] as! String
// let url = URL(string: photoURL)
// let timestamp = comments["timestamp"] as! Double
print(degree)
}
}
})
}
The answer by #aytroncb is a good answer, I prefer to leave Firebase data 'Firebasy' as long as possible. In other words coverting to dictionaries looses ordering and and find code like this
[String: [String: [String: Any]]]
To be very hard to read.
I prefer
let snap = snapshot.childSnapshot("comments") //snap becomes a DataSnapshot
So my solution maintains the order and leverages .childSnapshot to leave data in it's DataSnapshot form.
func readPostComments() {
let postRef = self.ref.child("posts") //self.ref points to my firebase
postRef.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
print("postId: \(postSnap.key)")
let commentsSnap = postSnap.childSnapshot(forPath: "comments") //will be a DataSnapshot
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
print(" commentId: \(commentSnap.key)")
let replyDegree = commentSnap.childSnapshot(forPath: "reply_degree").value as? String ?? "No Degree"
let replyName = commentSnap.childSnapshot(forPath: "reply_name").value as? String ?? "No Name"
print(" degree: \(replyDegree) by: \(replyName)")
}
}
})
}
EDIT
For a single post, remove the top part of the code that reads in and iterates over all posts.
func readCommentsForOnePost() {
let postRef = self.ref.child("posts")
let postCommentRef = postRef.child("post_0")
postCommentRef.observeSingleEvent(of: .value, with: { snapshot in
print("postId: \(snapshot.key)")
let commentsSnap = snapshot.childSnapshot(forPath: "comments") //will be a DataSnapshot
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
print(" commentId: \(commentSnap.key)")
let replyDegree = commentSnap.childSnapshot(forPath: "reply_degree").value as? String ?? "No Degree"
let replyName = commentSnap.childSnapshot(forPath: "reply_name").value as? String ?? "No Name"
print(" degree: \(replyDegree) by: \(replyName)")
}
})
}
Its because firebase is returning your data like this
{
"MAKFW244kdL)Cw;1": [Array of data],
"LOPSw!35pa3flAL4": [Array of data],
"ALV34VR4_A6Vn1a": [Array of data]
}
So change your initial casting of snapshot.value to this:
if let dict = snapshot.value as? [String: [String: Any]]
then loop through that new dictionary like this:
for objectJson in dict.values {
if let comments = objectJson["comments"] as? [String: [String: Any]] {
for commentJson in comments.values {
let degree = commentJson["reply_degree"] as? String
}
}
}
Update
Just read through your post again and noticed your trying to access the comments directly with a key, your first going to need to provide the PostId. Then you can use the above code to loop through the objects
let postRef = Database.database().reference().child("posts").child(postID)
alternatively I believe you can have the comments returned as a normal list by doing something like this:
let postRef = Database.database().reference().child("posts").child("\(postID)/{id}")

How to unwrap an callback in swift?

I'm using FB Login for my app in Swift and when I make a graph request, it returns the following result:
Optional({
email = "arjun.ramjams#gmail.com";
id = 10218497873670001;
name = "Arjun Ram";
})
Now, how should I read, each individual value(i.e: email, id and name)?
func fetchProfile() {
let parameters = ["fields": "id,email, first_name, last_name"]
GraphRequest(graphPath: "me",parameters: parameters).start{(connection, user, Err) in
if Err != nil {
print(Err!)
return
}
let dic = user as! NSDictionary
let userID = dic["id"] as! String
let Email = dic["email"] as! String
let fname = dic["first_name"] as! String
let lname = dic["last_name"] as! String
}
}
The result is a Dictionary of type [String:Any]?.
let result:[String:Any]? = [
"email":"arjun.ramjams#gmail.com",
"id" : 10218497873670001,
"name":"Arjun Ram"
]
You can fetch the fields from result like,
let email = result?["email"] as? String
let id = result?["id"] as? Int
let name = result?["name"] as? String
You need to use if let or guard let for unwraping an object or variable
e.g.:
if let result = result as? [String: Any] {
print(result[“email”])
}
or
guard let result = result as? [String: Any] else {
// return something
}

save current location to plist when the user enters Geofencing radius

i am working on a geofencing app. i need to save user current location to a plist when the user enters geofencing radius which i have extracted them from a db file. How to do it? i am new to this. please Help.. i extracted from db file like this..
func readvalues(){
let path = Bundle.main.path(forResource: "NewFile", ofType: "db")
let database = FMDatabase(path: path)
if !database.open() {
print("Unable to open database")
return
}
if let rs = database.executeQuery("SELECT * FROM myowntable", withArgumentsIn: []) {
while rs.next() {
print("%#", rs);
geotifications = []
let longitude = rs.string(forColumn: "longitude") as! String
let latitude = rs.string(forColumn: "latitude") as! String
let note = rs.string(forColumn: "note") as! String
let radiusstring = rs.string(forColumn: "radius") as! String
let radius = (radiusstring as NSString).doubleValue
let identifier = rs.string(forColumn: "identifier") as! String
let event = Int(rs.string(forColumn: "eventType")!)!
let eventType: EventType = (event == 0) ? .onEntry : .onExit
let location:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: (latitude as NSString).doubleValue, longitude: (longitude as NSString).doubleValue)
self.addGeotificationViewController(didAddCoordinate: location, radius: radius, identifier: identifier, note: note, eventType: eventType)
}
} else {
print("executeQuery failed: \(database.lastErrorMessage())")
}
database.close()
}
You not able to change apps plist file, so you need create your own plist file
let fileManager = FileManager.default
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let path = documentDirectory.appending("/geo.plist")
if(!fileManager.fileExists(atPath: path)){
print(path)
let data : [String: String] = [
"geoPointX": "20",
"geoPointY": "30"
]
let someData = NSDictionary(dictionary: data)
let isWritten = someData.write(toFile: path, atomically: true)
print("is the file created: \(isWritten)")
} else {
print("file exists")
}

Switch from NSDictionary to Dictionary

I have some code to get EXIF data from file, but it uses NS-Types. I like to get Swift 3 conform and use standard swift types like Dictionary or String. When deleting "NS", I get the error that ".value()" does not exist. And no hint by the compiler what is the new function call:
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as NSDictionary
let exifDict = imageProperties.value(forKey: "{Exif}") as! NSDictionary
let dateTimeOriginal = exifDict.value(forKey: "DateTimeOriginal") as! NSString
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict.value(forKey: "PixelXDimension") as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties.value(forKey: "{TIFF}") as! NSDictionary
// optional
if let Software = exifDictTIFF.value(forKey: "Software") as? NSString {
print ("Software: \(Software)")
}
Any hint how to change it?
Additionally:
Using this
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as Dictionary
let exifDict = imageProperties["{Exif}"] as! Dictionary
will deliver an error "Ambiguous reference to member 'subScript'" for the second row!
All of the NSDictionary needs to be something like [String:Any]. And all of the value calls should use normal key access.
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil) as! [String:Any]
let exifDict = imageProperties["{Exif}"] as! [String:Any]
let dateTimeOriginal = exifDict["DateTimeOriginal"] as! String
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict["PixelXDimension"] as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties["{TIFF}"] as! [String:Any]
// optional
if let Software = exifDictTIFF["Software"] as? String {
print ("Software: \(Software)")
}
This code is terrible. All of those uses of ! are a bad idea. Proper, safe unwrapping and casting should be used throughout this code.

How to access a dictionary value with Swift 3?

So since the release of Swift 3, a part of my code where I access a dictionary isn't working anymore, here is the code with the previous release of swift:
var locationDict: NSDictionary?//location dictionary
if let getLocation = item.value?["Location"]{locationDict = getLocation as? NSDictionary}
//get dictionary values
let getLatitude = locationDict?.valueForKey("latitude") as! Double
let getLongitude = locationDict?.valueForKey("longitude") as! Double
Now with the new release I'm not sure how to rewrite "getLocation". I only rewrote the last two lines with the new syntax:
//get dictionary values
let getLatitude = locationDict?.value(forKey: "latitude") as! Double
let getLongitude = locationDict?.value(forKey: "longitude") as!
I am using Firebase, this is the complete function: (it adds an array of annotations to a map)
func setAnnotations(){
//get data
ref.child("Stores").observe(.value, with: { (snapshot) in
self.mapView.removeAnnotations(self.annArray)
for item in snapshot.children {
let annotation = CustomAnnotation()
//set all data on the annotation
annotation.subtitle = (snapshot.value as? NSDictionary)? ["Category"] as? String
annotation.title = (snapshot.value as? NSDictionary)? ["Name"] as? String
annotation.annImg = (snapshot.value as? NSDictionary)? ["Logo"] as? String
var locationDict: NSDictionary?//location dictionary
if let getLocation = item.value?["Location"]{locationDict = getLocation as? NSDictionary}
let getLatitude = locationDict?.value(forKey: "latitude") as! Double
let getLongitude = locationDict?.value(forKey: "longitude") as! Double
annotation.coordinate = CLLocationCoordinate2D(latitude: getLatitude, longitude: getLongitude)
self.annArray.append(annotation)
self.mapView.addAnnotation(annotation)
}
})
}
Try this:-
func setAnnotations(){
//get data
FIRDatabase.database().reference().child("Stores").observe(.value, with: { (snapshot) in
self.mapView.removeAnnotations(self.annArray)
for item in snapshot.children{
if let itemDict = (item as! FIRDataSnapshot).value as? [String:AnyObject]{
annotation.subtitle = itemDict["Category"] as! String
annotation.title = itemDict["Name"] as! String
annotation.annImg = itemDict["Logo"] as! String
if let locationDict = itemDict["Location"] as? [String:AnyObject]{
let getLatitude = locationDict["latitude"] as! Double
let getLongitude = locationDict["longitude"] as! Double
annotation.coordinate = CLLocationCoordinate2D(latitude: getLatitude, longitude: getLongitude)
self.annArray.append(annotation)
self.mapView.addAnnotation(annotation)
}
}
}
})
}
Things get substantially easier if you cast to a type-safe dictionary, e.g.:
snapshot.value! as! [String:Any]
For a slightly larger example, see the code from this answer I wrote earlier today:
ref!.observe(.value, with: { (snapshot) in
for child in snapshot.children {
let msg = child as! FIRDataSnapshot
print("\(msg.key): \(msg.value!)")
let val = msg.value! as! [String:Any]
print("\(val["name"]!): \(val["message"]!)")
}
})