Swift 3 JsonSerialization - swift3

Code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnGirisYap(_ sender: Any) {
let url = NSURL(string: "http://www.kerimcaglar.com/yemek-tarifi")!
let task = URLSession.shared.dataTask(with: url as URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:AnyObject]
//print (jsonResult)
self.txtGirisKullaniciAdi.text = jsonResult["malzemeler"] as! NSString as String
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
}
task.resume()
}
}
Can you help with this?

The error message tells you clearly that the deserialized object is an array rather than a dictionary.
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as! [[String:Any]]
for item in jsonResult {
print(item["malzemeler"] as! String) // cast directly to String
}
Notes:
The unspecified JSON dictionary type in Swift 3 is [String:Any].
The mutableContainers option is useless in Swift.

Related

Convert HTML text to displayable text in swiftUI [duplicate]

I was wondering how can HTML tags be stripped out of JSON from a web url. Do I have to use NSString of something similar.
So I am looking to strip out the html tags that are in the summary value. I looked around abit and it says NSString can be used but I was not sure if that was something that could be implemented into Swift 3. Any Help would be appreciated.
My code:
import UIKit
import Alamofire
struct postinput {
let mainImage : UIImage!
let name : String!
let author : String!
let summary : String!
}
class TableViewController: UITableViewController {
var postsinput = [postinput]()
var mainURL = "https://www.example.com/api"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callAlamo(url: mainURL)
}
func callAlamo(url : String){
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
// print(readableJSON)
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
let author = post["author"] as! String
guard let dic = post["summary"] as? [String: Any], let summary = dic["value"] as? String else {
return
}
print(author)
if let imageUrl = post["image"] as? String {
let mainImageURL = URL(string: imageUrl )
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title, author: author, summary: summary))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsinput.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = postsinput[indexPath.row].mainImage
//(cell?.viewWithTag(2) as! UIImageView).image = postsinput[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = postsinput[indexPath.row].name
mainLabel.font = UIFont(name: "Helvetica", size:14)
let autLabel = cell?.viewWithTag(3) as! UILabel
autLabel.text = postsinput[indexPath.row].author
autLabel.font = UIFont(name: "Helvetica", size:12)
let sumLabel = cell?.viewWithTag(4) as! UILabel
sumLabel.text = postsinput[indexPath.row].summary
sumLabel.font = UIFont(name: "Helvetica", size:12)
//(cell?.viewWithTag(3) as! UILabel).text = postsinput[indexPath.row].author
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can use this code for stripping html tags
From your previous question
guard let dic = post["summary"] as? [String: Any], let summary = dic["value"] as? String else {
return
}
let str = summary.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str)
Edit
I have checked it and it is working
let summary = "<p>Latin text here</p>"
let str = summary.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str)
Latin text here

I Found Error of Could Not Cast Value of Type when i load my json in Tableview

This is my code , could not append array type to UIImage , api is successfully loaded , i have problem in appending data
var images = UIImage
func downloadJsonWithURL() {
let url = NSURL(string: urlString)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSObject {
print(jsonObj!.value(forKey: "guid"))
if let actorArray = jsonObj!.value(forKey: "guid") as? [NSObject] {
if let actorDict = actorArray as? NSObject
{
if let name = actorDict.value(forKey: "rendered") {
**self.images.append(name as! UIImage)**
print("\(name)")
}
}
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}).resume()
}
this is my rest api
guid {1}
rendered : http://thenewschef.com/wp-content/uploads/2018/02/startup.jpeg
So, You Can Do This
var images = [[String:AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
downloadJsonWithURL()
}
//Tableview methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return images.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 135
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DemoTableCell", for: indexPath) as! DemoTableCell
let dict = images[indexPath.row]
URLSession.shared.dataTask(with: NSURL(string: dict["rendered"] as! String)! as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error as Any)
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
cell.imgView?.image = image
})
}).resume()
return cell
}
//your api call
func downloadJsonWithURL() {
let urlString = "https://thenewschef.com/wp-json/wp/v2/media"
let url = NSURL(string: urlString)
print(url as Any)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) {
print((jsonObj as AnyObject).value(forKey: "guid") as Any)
let responseJSON = (jsonObj as AnyObject).value(forKey: "guid") as Any
let json = (responseJSON as AnyObject) as? NSArray
self.images = json as! [[String:AnyObject]]
print(self.images)
OperationQueue.main.addOperation({
self.demoTable.reloadData()
})
}
}).resume()
}
That's it you got your UIImage.
Enhanced implementation of above solution using Higher order function to avoid all the cast dance.
Use the below code to fetch the response form Server & filter the required imageUrl's in a single array.
func downloadJsonWithURL() {
let urlString = "https://thenewschef.com/wp-json/wp/v2/media"
let url = NSURL(string: urlString)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {[weak self] (data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) {
let guids = (jsonObj as? [[String: Any]])?.map { $0["guid"] }
let imagesArray = (guids as? [[String: Any]])?.map {$0["rendered"]} as? [String]
OperationQueue.main.addOperation({
//Reload Table here...
})
}
}).resume()
}

UserDefaults.standard not saving swift3 xcode 8

Hello everybody I'm trying to build a simple one view program to call and navigate a voice menu, I cannot get the UserDefaults to properly save between closing of the app. I've also had issue with getting text to display in the UITextField, I would like for it to display if saved on launch, here is a description of vars:
UserInput - text field for employee ID (what needs saving)
Switch - if Save it is 1 save data, if 0 do not
Submit - submit button that should save the data and call.
This is my first iPhone app and any help would be much appreciated!
enter code here
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var UserInput: UITextField!
var SaveIt = true
var employID = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.UserInput.delegate = self;
UserInput.keyboardType = .numberPad
if let current_eid = UserDefaults.standard.string(forKey: "emp_ID") {
UserInput.text = current_eid
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadDefaults() {
let defaults = UserDefaults.standard
if let UserInput = defaults.string(forKey: "emp_ID") {
print(UserInput)
} else {
// focus on the text field if it's empty
UserInput.becomeFirstResponder() }
UserInput.text = defaults.object(forKey: "emp_ID") as! String?
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
#IBAction func Switch(_ sender: UISwitch) {
if (sender.isOn == true) {
SaveIt = true
}
else{
SaveIt = false
}
}
#IBAction func Submit(_ sender: Any) {
if (SaveIt) {
let defaults = UserDefaults.standard
defaults.set(UserInput.text, forKey: "emp_ID")
defaults.synchronize()
}
let phone = "telprompt://1888247889pppp" + UserInput.text! + "p1p1p1p1";
let url = URL(string:phone)!
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else { UIApplication.shared.openURL(url)
}
}
}

Passing an array using protocols/delegates

I have tried over and over to get this to work, but to no avail. I am trying to pass an array from a SendingVC to a ReceivingVC and display the content of that array in two labels.
SendingVC Code:
import UIKit
protocol SenderVCDelegate {
func passArrayData(data: [String])
}
class SendingVC: UIViewController {
// DELEGATE
var delegate: SenderVCDelegate?
var carDetails: [String]? = ["BMW", "X5"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func unwindToFirst(segue: UIStoryboardSegue) {
//
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if (carDetails?.isEmpty)! {
return false
} else {
if let delegate = delegate, let data = carDetails {
delegate.passArrayData(data: data)
print("from inside segue: \(data)")
}
return true
}
}
}
ReceivingVC Code
import UIKit
class ReceivingVC: UIViewController, SenderVCDelegate {
#IBOutlet weak var lbl01: UILabel!
#IBOutlet weak var lbl02: UILabel!
var incomingCarDetails: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
print("from inside viewLoad: \(incomingCarDetails)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if let sendingVC: SendingVC = segue.destination as? SendingVC {
sendingVC.delegate = self
}
}
func passArrayData(data: [String]) {
incomingCarDetails = data
populateLabels(array: incomingCarDetails)
}
func populateLabels(array: [String]) {
for (index, value) in array.enumerated() {
switch index {
case 0:
lbl01.text = value
case 1:
lbl02.text = value
default:
break
}
}
}
}
Any help would be appreciated! :)
Thanks!
You seem to have confusion around the role of a delegate and where it should be implemented. You don't need to use a delegate to pass data from SendingVC to RecevingVC, you can simply set the property on the destination view controller in prepareForSegue;
class SendingVC: UIViewController {
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destinationViewController as? ReceivingVC {
destVC.incomingCarDetails = self.carDetails
}
}
}
If you do want to use a delegate, then you will set the SendingVC instance as the delegate of your ReceivingVC in prepareForSegue and change your protocol so that the delegate method returns data, rather than accepts data:
protocol SenderVCDelegate {
func passArrayData() -> [String]
}
Then, you can implement the delegate method and set the delegate in prepareForSegue
class SendingVC: UIViewController, SenderVCDelegate {
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destinationViewController as? ReceivingVC {
destVC.senderDelegate = self
}
}
func passArrayData() -> [String] {
return self.carDetails
}
}
In ReceivingVC you can call the delegate method in viewWillAppear
class ReceivingVC: UIViewController {
var incomingCarDetails = [String]()
var senderDelegate: SenderVCDelegate?
override func viewWillAppear(animated: bool) {
super.viewWillAppear(animated)
if let incomingDetails = self.senderDelegate?.passArrayData() {
self.incomingCarDetails = incomingDetails
}
}
}
As you can see this is a whole lot more work and no benefit. A delegation pattern is typically used where you want to send data back and where the function call will happen at an unpredictable time, such as in response to a network operation completing or a user interaction.

Updating an URLSession to swift 3 throwing error

I updated my code to Swift 3 and most of it converted over fine except from the URLSession and I cant find a solution to this error:
Cannot invoke 'dataTask' with an argument list of type '(with: NSMutableURLRequest, completionHandler: (Data?, URLResponse?, NSError?) -> Void)'
This is my code:
let post:NSString = "username=\(username)&userPassword=\(password)&userEmail=\(email)" as NSString
let url:URL = URL(string: "http://ec2-54-201-55-114.us-west-2.compute.amazonaws.com/wickizerApp/ApplicationDB/scripts/registerUser.php")!
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post.data(using: String.Encoding.utf8.rawValue)
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:NSError?) -> Void in
DispatchQueue.main.async
{
if error != nil {
self.displayAlertMessage(error!.localizedDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let status = parseJSON["status"] as? String
if( status! == "200")
{
let myAlert = UIAlertController(title: "Alert", message: "Registration successful", preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default){(action) in
self.dismiss(animated: true, completion: nil)
}
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
} else {
let errorMessage = parseJSON["message"] as? String
if(errorMessage != nil)
{
self.displayAlertMessage(errorMessage!)
}
}
}
} catch{
print(error)
}
}
}).resume()
Is there a different way to do requests in swift 3 or did they just change the way to do them?
The compiler wants URLRequest and Error
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post.data(using: .utf8)
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) -> Void in
})
or still shorter
URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
})
or still shorter
URLSession.shared.dataTask(with: request) { (data, response, error) in
}