How to decode a base64 to string Swift [duplicate] - json

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 1 year ago.
I'm trying to get the readme data for a selected repository from the GitHub api. So, the "content" is the content of the readme file, but is a base64 type. I tried to convert it but when I'm running the app, I get a fatal error "Fatal error: Unexpectedly found nil while unwrapping an Optional value "
Code:
class DetailsViewController: UIViewController {
var details: Item?
var read: Readm?
#IBOutlet weak var forksLabel: UILabel!
#IBOutlet weak var starLabel: UILabel!
#IBOutlet weak var readMeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
forksLabel.text = "\(details!.forks_count)"
starLabel.text = "\(details!.stargazers_count)"
downloadJSON {
return
}
readMeLabel.text = decodeBase64(word: read!.content) // <- here is the error
}
func downloadJSON (completed: #escaping () -> ()) {
let url = URL (string: "https://api.github.com/repos/\(details!.full_name)/readme")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
print("ceva")
self.read = try JSONDecoder().decode(Readm.self, from: data!)
DispatchQueue.main.async {
completed()
}
}catch {
print (error)
}
}
}.resume()
}
func decodeBase64(word: String) -> String {
let base64Decoded = Data(base64Encoded: word)!
let decodedString = String(data: base64Decoded, encoding: .utf8)!
return decodedString
}
}
This is where the error is :
readMeLabel.text = decodeBase64(word: read!.content)
EDITED:
super.viewDidLoad()
forksLabel.text = "\(details!.forks_count)"
starLabel.text = "\(details!.stargazers_count)"
downloadJSON {
if let content = self.read?.content {
self.readMeLabel.text = self.base64Decoded(word: content)
print(self.base64Decoded(word: content))
}
}
}
func base64Decoded(word: String) -> String? {
guard let base64Data = Data(base64Encoded: word) else { return nil}
let decodedData = String(data: base64Data, encoding: .utf8)
return decodedData
}
I have managed how to unwrap things, but now, my label is empty, I made a print statement and is nil. Anyone know why ?

As you have already an asynchronous completion handler use it!.
A single return statement is pretty pointless, move the line to assign the text into the closure.
And unwrap the value always safely, because an error could occur
downloadJSON {
if let content = self.read?.content {
self.readMeLabel.text = self.decodeBase64(word: content)
}
}

Related

How to return JSON data from Swift URLSession [duplicate]

This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 1 year ago.
I'm trying to return json data from an api call. I'm able to access the json data successfully but am struggling to find a way / the best way to return it for access in my app. Thanks for any ideas!
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// make the api call and obtain data
let data = self.loadData()
print("inside viewDidLoad", data) // prints 'inside viewDidLoad emptyString'
}
func loadData() -> String {
var circData = "emptyString"
let session = URLSession.shared
let url = URL(string: "https://us-east-1.aws.webhooks.mongodb-realm.com/api/client/v2.0/app/cirdata-khyvx/service/cirData/incoming_webhook/cirlAPI")!
let task = session.dataTask(with: url, completionHandler: { data, response, error in
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) {
// print("json: ", json) // prints the whole json file, verifying the connection works. Some 300kb of data.
// print("json file type: ", type(of: json)) // prints '__NSArrayI'
let jsonString = "\(json)"
circData = jsonString
// print("circData", circData) // prints the whole json file, verifying that the json string has been assigned to 'circData'
}
})
task.resume()
// print("after: ", circData) // prints 'after: emptyString'. It's as if the reassignment didn't take place.
return circData
}
}
You can't return a value synchronously becuase the api call that is fetching json data is asynchronous. You need to use a completion handler instead.
You can put breakpoints in different places inside the code to understand how the flow executes.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.loadData(completion: { [weak self] (result, error) in
if let error = error {
print(error.localizedDescription)
}
if let result = result {
print(result)
}
})
}
func loadData(completion: #escaping (_ data: Any?, _ error: Error?) -> Void) {
let url = URL(string: "https://us-east-1.aws.webhooks.mongodb-realm.com/api/client/v2.0/app/cirdata-khyvx/service/cirData/incoming_webhook/cirlAPI")!
let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
if let error = error {
completion(nil, error)
return
}
do {
if let data = data {
let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments])
completion(json, nil)
} else {
completion(nil, nil)
}
} catch {
completion(nil, error)
}
})
task.resume()
}
}

Why getting nil in collectionView image from json in swift

I have collectionview with image and label... I'm able to display text values from json to label and I'm getting all img urls from json to cellForItemAtindexPath but all those images i am unable to show in collectionview.. i have all 20 image urls in cellForItemAtindexPath i can see it in console but why i am unable to display them in collectionview.
here is my code:
import UIKit
import SDWebImage
struct JsonData {
var iconHome: String?
var typeName: String?
var id: String?
init(icon: String, tpe: String, id: String) {
self.iconHome = icon
self.typeName = tpe
self.id = id
}
}
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITextFieldDelegate, URLSessionDelegate {
#IBOutlet weak var collectionView: UICollectionView!
var itemsArray = [JsonData]()
override func viewDidLoad() {
super.viewDidLoad()
homeServiceCall()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemsArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HomeCollectionViewCell
let aData = itemsArray[indexPath.row]
cell.paymentLabel.text = aData.typeName
cell.paymentImage.sd_setImage(with: URL(string:aData.iconHome!)) { (_, error, _, _) in
if let error = error {
print(error)
}
}
print("tableview collection images \(String(describing: aData.iconHome))")
return cell
}
//MARK:- Service-call
func homeServiceCall(){
let urlStr = "https://********/webservices//getfinancer"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
guard error == nil else {
print("error")
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
let financerArray = jsonObj["financer"] as! [[String: Any]]
for financer in financerArray {
guard let id = financer["id"] as? String else { break }
guard let pic = financer["icon"] as? String else { break }
guard let typeName = financer["tpe"] as? String else { break }
print("the json icons \(String(describing: pic))")
let jsonDataObj = JsonData(icon: pic, tpe: typeName, id: id)
self.itemsArray.append(jsonDataObj)
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
}
when i print image urls in cellForItemAtindexPath i got all 20 image urls in console.. but why i am unable to show them in collectionview.
i am getting output like below.. some images are showing and some are not if i give placeholder image in sd_setImage then it shoes placeholder image in collectionview why??
here is my output:
some images are coming and some are not but there are no nil images in server all images are coming in json.. i got stuck here from long time.. anyone please help me here.
Because you are using Swift so i recommend that you should use KingFisher instead of SDWebImage to handle images from urls.
I checked your code, everything is fine. However, when you load image from url, some of them throw this error:
A URL session error happened. The underlying error: Error Domain=NSURLErrorDomain Code=-1202 \"The certificate for this server is invalid. You might be connecting to a server that is pretending to be “anyemi.com” which could put your confidential information at risk."
This error happens for urls with domain anyemi.com.
For example:
https://anyemi.com/PaySTAR/images/LSPUBLICSCHOOL_icon.png
https://anyemi.com/PaySTAR/images/CDMA_icon.png
Urls with domain dev.anyemi.com work well. For example:
https://dev.anyemi.com/maheshbank/icons/electricity.png
https://dev.anyemi.com/maheshbank/icons/gas.png
Therefore the problem is in SSL configuration of your backend. For now, you can change the url with domain anyemi.com to dev.anyemi.com for testing and i believe that it will work well.

json data not getting loaded into UITextView in swift

class ViewController:ViewController,UITextViewDelegate{
#IBOutlet weak var newTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
newTextView.delegate = self
dataFun()
}
func dataFun()
{
let url : String = "http:xyz/abc"
let request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
print("Start")
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
let jsonResult: NSDictionary! = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as? NSDictionary
print("In method\(jsonResult)")
// let data = jsonResult["description"]
// print(data!)
if (jsonResult != nil)
{
// process jsonResult
print("Data added")
let test:String = jsonResult["description"] as! String
print(test)
self.newTextView.text = test
} else {
print("No Data")
// couldn't load JSON, look at error
}
}
catch {
print("Error Occured")
}
}
.resume()
}
In my app I am going to call services from API
I can see my json data in console.
that data is not show in textviewController
it shows fatal error:
unexpectedly found nil while unwrapping an Optional value
and then crash the app
Make sure #IBOutlet weak var newTextView: UITextView! is set up correctly.
Make sure let test:String = jsonResult["description"] as! String doesn't crash. JSON has field description and it's a string.

Swift HTML Parser

I am having trouble posting the outputs to a label. I have to covert it to a String? The error it seems to give me is "Cannot subscript a value of type JiNode? with an index of type 'Int'" Please help!
var meter = ""
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let url = NSURL(string: "http://uberestimate.com/costs.php")
let jiDoc = Ji(htmlURL: url!)
if jiDoc != nil {
print("html retrived.\n")
self.scrapeHTML(jiDoc!)
}
}
}
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var endingPoint: UITextField!
#IBOutlet weak var startingpoint: UITextField!
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.
}
private func scrapeHTML(jiDoc: Ji) {
println("parsing...\n")
let bodyNode = jiDoc.xPath("//body")!.first!
var contentDivNode = bodyNode.xPath("//span[#style='font-size:1.3em']").first
if contentDivNode == nil {
print("unexpected format!")
}else{
var cdnArray = contentDivNode[1]
var cdn = cdnArray[0]! as String
self.resultLabel.text = cdn
// println(contentDivNode)
}
return
}
}
You can do something like:
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
let url = NSURL(string: "http://uberestimate.com/costs.php")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { data, response, error in
if data == nil || error != nil { // in Swift 2, I'd use `guard`, but I tried to keep this backward compatible
print(error)
return
}
dispatch_async(dispatch_get_main_queue()) {
self.scrapeHTML(data!)
}
}
task.resume()
}
private func scrapeHTML(data: NSData) {
print("parsing...\n")
let jiDoc = Ji(data: data, isXML: false)
if let contentDivNode = jiDoc?.xPath("//span[#style='font-size:1.3em']")?.first {
self.resultLabel.text = contentDivNode.content
}
}
I'm using the Swift 2.1 (and I infer from the presence of println that you must be using an earlier version), but I think this is largely the same regardless of Swift version.
BTW, notice that I am dispatching the update of the label back to the main queue (as you called scrapeHTML from a global queue, but UI updates must happen on the main thread). I'm also using NSURLSession rather than dispatching a synchronous network request to a global queue.

Passing JSON data to a label in Swift

I'm new to coding and have a (hopefully easy) question.
I am trying to display JSON data as a label using swift. I'm not getting any errors but nothing is showing up using the following code:
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, ErrorType) -> Void in
if let urlContent = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
print(jsonResult)
let text = jsonResult as? String
self.textLabel.text = text
} catch {
print("JSON serialization failed")
}
}
}
task.resume()
Thanks!
Just update your label into main thread this way:
dispatch_async(dispatch_get_main_queue()) {
self.textLabel.text = text
}
UPDATE:
You can use SwiftyJSON for that.
And below is your working code with that library:
import UIKit
class ViewController: UIViewController {
var dict = NSDictionary()
#IBOutlet weak var authorLbl: UILabel!
#IBOutlet weak var quoteLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "http://api.theysaidso.com/qod.json"
if let url = NSURL(string: urlString) {
if let data = try? NSData(contentsOfURL: url, options: []) {
let json = JSON(data: data)
print(json)
let auther = json["contents"]["quotes"][0]["author"].stringValue
let quote = json["contents"]["quotes"][0]["quote"].stringValue
authorLbl.text = auther
quoteLbl.text = quote
}
}
}
}