Getting error after initialising json api in swift - arrays

I got everything working so far. When building the project and running the function it parses the api content and then crashes.
Here is the code:
//
// GamesTableViewController.swift
// Football Life
//
// Created by David Seyboth on 18/01/16.
// Copyright © 2016 David Seyboth. All rights reserved.
//
import UIKit
class GamesTableViewController: UITableViewController {
// MARK: Properties
var gameplan = [Games]()
override func viewDidLoad() {
super.viewDidLoad()
//load NFL Games
loadNFLgames { (result) -> () in
self.gameplan = result
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})
}
}
func loadNFLgames(completionClosure: (result : [Games]) ->()){
let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue, {
let URL = "http://www.fantasyfootballnerd.com/service/schedule/json/test/"
print(URL)
if let data = NSData(contentsOfURL: NSURL(string: URL)!){
if let JsonObject = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSMutableDictionary{
print(JsonObject)
let homeTeam = JsonObject["homeTeam"] as! String
let awayTeam = JsonObject["awayTeam"] as! String
let gameDate = JsonObject["gameDate"] as! String
let gameTimeET = JsonObject["gameTimeET"] as! String
let tvStation = JsonObject["tvStation"] as! String
let api_guest = awayTeam
let api_home = homeTeam
let api_tvhost = tvStation
let api_time = gameDate + ", " + gameTimeET + " ET" // convert gameDate to day e.g. SUN
let api_stadion = "N/A"
// prepare data for array
let gamedata = Games(participants: api_guest+" # "+api_home, photoguest: UIImage(named: api_guest), photohome: UIImage(named: api_home), time: api_time, stadium: api_stadion, channel: api_tvhost)!
self.gameplan.append(gamedata)
completionClosure(result: self.gameplan)
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return gameplan.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "GamesPrototypeCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! GamesTableViewCell
// Fetches the appropriate meal for the data source layout.
let game = gameplan[indexPath.row]
cell.participants_label.text = game.participants
cell.photoguest_image.image = game.photoguest
cell.photohome_image.image = game.photohome
cell.time_label.text = game.time
cell.stadium_label.text = game.stadium
cell.channel_label.text = game.channel
return cell
}
}
the crash is at line:
let homeTeam = JsonObject["homeTeam"] as! String
with the message:
fatal error: unexpectedly found nil while unwrapping an Optional value

you are missing the json format. the values your looking for are in array "Schedule"
so your code will be
if let JsonObject = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSMutableDictionary{
//this is your array of games
let items = JsonObject["Schedule"] as! NSMutableArray
print(items)
//loop in items and add the values to your array
for item in items {
let homeTeam = item["homeTeam"] as! String
let awayTeam = item["awayTeam"] as! String
let gameDate = item["gameDate"] as! String
let gameTimeET = item["gameTimeET"] as! String
let tvStation = item["tvStation"] as! String
let api_guest = awayTeam
let api_home = homeTeam
let api_tvhost = tvStation
let api_time = gameDate + ", " + gameTimeET + " ET" // convert gameDate to day e.g. SUN
let api_stadion = "N/A"
// prepare data for array
let gamedata = Games(participants: api_guest+" # "+api_home, photoguest: UIImage(named: api_guest), photohome: UIImage(named: api_home), time: api_time, stadium: api_stadion, channel: api_tvhost)!
self.gameplan.append(gamedata)
}
}

Related

SWIFT 5.1 Get array of strings ( image names ) from directory and append to an array of UIImages

Goal is to get the image names from a directory and add them to an array of UIImages.
var photoArray = [UIImage]()
func getImageFromDocumentDirectory() -> [UIImage] {
let fileManager = FileManager.default
var imageNames = [String]()
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)[0] as NSString).appendingPathComponent("DIRECTORYNAME")
do {
let items = try fileManager.contentsOfDirectory(atPath: imagePath)
for item in items {
This is where I'm getting the problem: error: Found nil ( let images )
let images = UIImage(contentsOfFile: item)
photoArray.append(images!)
}
} catch {
print(error.localizedDescription)
}
return photoArray
}
Adding the func to a collection View to pull images.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
-> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL",
for: indexPath) as! CELL
let images = getImageFromDocumentDirectory()
// photoImageView is a UIImageView in the cell.
cell.photoImageView.image = images[indexPath.row]
}
The problem is that – as you mentioned correctly – contentsOfDirectory(atPath returns an array of image names. To read the images from disk you need the full path.
I recommend to use the URL related API
func getImageFromDocumentDirectory() -> [UIImage] {
var images = [UIImage]()
let fileManager = FileManager.default
do {
let documentsDirectoryURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let folderURL = documentsDirectoryURL.appendingPathComponent("DIRECTORYNAME")
let urls = try fileManager.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for url in urls {
if let data = try? Data(contentsOf: url),
let image = UIImage(data: data) {
images.append(image)
}
}
} catch {
print(error.localizedDescription)
}
return images
}

Unable to add json key values in array why in swift

My json contains image, type and id.. here i want my ids in separate individual array called idArray.. here i am able to get single id in log, i have append ids to idArray but i am not getting ids in array it shows nil why?
i have taken idArray as string. please help me in code.
here is my json structure:
{
"financer": [
{
"id": "45",
"icon": "https://hello.com//images/img1.png"
"tpe": "bank"
}
{
"id": "40",
"icon": "https://hello.com//images/img2.png"
"tpe": "wallet"
}
.
.
.
]
}
here is my code:
import UIKit
import SDWebImage
struct JsonData {
var iconHome: String?
var typeName: String?
init(icon: String, tpe: String) {
self.iconHome = icon
self.typeName = tpe
}
}
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITextFieldDelegate {
#IBOutlet weak var collectionView: UICollectionView!
var itemsArray = [JsonData]()
var idArray = [String]()
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!), placeholderImage: UIImage(named: "GVMC_icon"))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "MakePaymentViewController") as? MakePaymentViewController
{
nextViewController.financerId = idArray[indexPath.row]
self.navigationController?.pushViewController(nextViewController, animated: true)
}
else{
AlertFun.ShowAlert(title: "", message: "will update soon..", in: self)
}
}
//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]
//print("the home json is \(jsonObj)")
let financerArray = jsonObj["financer"] as! [[String: Any]]
print("home financerData \(financerArray)")
for financer in financerArray {
let id = financer["id"] as? String
let pic = financer["icon"] as? String
let typeName = financer["tpe"] as! String
print("home financer id \(String(describing: id))")
self.idArray.append(id ?? "")
print("the home financer idsArray \(self.idArray.append(id ?? ""))")
self.itemsArray.append(JsonData(icon: pic ?? "", tpe: typeName))
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
}
Unable to json ids in separate array please help me in my code.
Don't use multiple arrays as data source. That's very bad practice.
Create two structs conforming to Decodable
struct Root : Decodable {
let financer : [Financer]
}
enum Type : String, Decodable {
case bank, wallet
}
struct Financer : Decodable {
let id : String
let icon : URL
let tpe : Type
}
Declare the data source array
var itemsArray = [Financer]()
and delete
var idArray = [String]()
Replace homeServiceCall with
func homeServiceCall() {
let url = URL(string: "https://dev.com/webservices/getfinancer")
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
if let error = error { print(error); return }
do {
DispatchQueue.main.async {
self.activityIndicator.startAnimating()
}
let result = try JSONDecoder().decode(Root.self, from: data!)
self.itemsArray = result.financer
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
catch {
print(error) -- print always the error instance.
}
}).resume()
}
In cellForRow get the id value with
let aData = itemsArray[indexPath.row]
cell.paymentLabel.text = aData.id
Important note:
Never never ever use synchronous Data(contentsOf to load data from a remote URL. Use an API which loads the data asynchronously and caches the images

How to Convert URL Images to UIImages in Swift5 and append into a array

I have an API call GET in Swift 5 Code for fetching the Images, I am getting url of the images , I have to change the url into UIImage to append the urls to a arrayimages=UIImage, data of the url is there but it is not appending to the arrayImages. my task is to put all the data images into the collection view ,if there is another way then guide me , Thanks.
--->. let arrayImages = UIImages
guard let data = response?.data(using: .utf8) else {
return
}
do {
let jsonObj = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
if jsonObj["error"] as! Bool == false {
print("galleryResponse/\(jsonObj)")
let jsonResponse = jsonObj["response"] as! [[String: Any]]
for i in 0...jsonResponse.count-1 {
let strGalleryImage = jsonResponse[i]["Gallery_Full"] as? String
if let imgurl = strGalleryImage {
self.userImageString1 = "\(USER_IMAGE_BASE_URL)\(imgurl)"
}
var imageString1: String?
var url1: URL!
imageString1 = self.userImageString1
if let imageUrlString1 = imageString1 {
url1 = URL(string: imageUrlString1)
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url1!){
if let imagedata = UIImage(data: data){
print("YES_IMG")
if data != nil {
DispatchQueue.main.async {
print("append_IMG")
self!.arrimages.append(imagedata)
}
}
}
}
}
}
//}
}
}
} catch {
print("Unable_to_load_data:/\(error)")
}
})
}
You can use AlamofireImage pod to convert the image URL to the image.
First, you need to install the pod file pod 'AlamofireImage'. Then import AlamofireImage in your ViewController.
Here is the way to implement that.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCollectionViewCellIdentifier", for: indexPath) as! YourCollectionViewCell
Alamofire.request("your image URL in String formate").responseImage { response in
debugPrint(response)
debugPrint(response.result)
if let image = response.result.value {
cell.YourImage.image = image
}
}
return cell
}
Hi I found out the Best solution i.e, through SDWebImages.
* Fist I get the response into url and then append it to a array = (String)[]
* then I called the sdwebimages in cellforitem function...
####CODE
// getting the url images into an array of string
let jsonResponse = jsonObj["response"] as! [[String: Any]]
print("galleryResponse/\(jsonObj)")
for i in 0...jsonResponse.count-1 {
let strGalleryImage = jsonResponse[i]["Gallery_Full"] as? String
print("o12\(strGalleryImage!)")
let str = String((strGalleryImage?.dropFirst(11))!) as? String
print("LAAL\(str)")
if let imgurl = str {
self.arrimages.append(imgurl)
print("kl\(self.arrimages)")
self.collectionView.reloadData()
}
THEN ->
//Calling the images into cellforitem
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
// called the url array into sd_setimages
cell.imgProfile.sd_setImage(with: URL(string: arrimages[indexPath.row]), placeholderImage: UIImage(named: "placeholder.jpg"))
return cell
}
Thanks for the answers but this is simplest solution of all...:)

Copy string to model (Swift 3)

My PhotoModel is returning nothing for eventDate()..
I have set it with
let newPhotos = PhotosModel() // Create the instance
newPhotos.eventDate = item.event_date! // Set the parameter
inside didSelectItemAt which when printed returns the correct date in the previous viewcontroller but isn't pushing it to the PhotoModel string.
If anyone could point me in the right direction or demonstrate what needs to be done that would be great, thank you.
ViewController:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.row)
// Configure the cell
let item: CoverModel = feedItems[indexPath.row] as! CoverModel
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "DetailCollectionViewController") as! DetailCollectionViewController
print(item.event_date!)
let newPhotos = PhotosModel() // Create the instance
newPhotos.eventDate = item.event_date! // Set the parameter
print(newPhotos.eventDate)
self.navigationController?.pushViewController(DvC, animated: true)
}
PhotosModel:
protocol PhotosProtocol: class {
func itemsDownloaded(items: NSArray)
}
class PhotosModel: NSObject, URLSessionDataDelegate {
//properties
weak var delegate: PhotosProtocol!
var eventDate = String()
var data = Data()
func downloadItems() {
let urlPath: String = "http://www.britanniaclub.co.uk/app_calls/britalbum.php?eventdate=\(eventDate)"
let url: URL = URL(string: urlPath)!
print("the event date is \(eventDate)")
print("the urlPath is \(urlPath)")
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Event Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
Output is:
2017-07-14
the event date is
the urlPath is http://www.britanniaclub.co.uk/app_calls/britalbum.php?eventdate=
Event Data downloaded
My guess is you are not assigning newPhotos to any property of DetailCollectionViewController. You will have to do it before pushing this view controller.

How to conform an array from another array that comes from a REST Service?

I’m trying to create a TableView with elements that comes from a REST Service, It’s a list of coupons that has description, title, category and images. So I deserialize the data first, put it in an array and then convert it into an specific array per each section, but my loop is not working, can anyone help me please?
This is my code:
var couponsTitle : [String] = []
var couponsDesc : [String] = []
var couponsCat : [String] = []
func getCoupons(){
let miURL = URL(string: RequestConstants.requestUrlBase)
let request = NSMutableURLRequest(url: miURL!)
request.httpMethod = "GET"
if let data = try? Data(contentsOf: miURL! as URL) {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
let parseJSON = json
let object = parseJSON?["object"] as! NSDictionary
let mainCoupon = object["mainCoupon"] as! NSArray
let coupons = object["coupons"] as! NSArray
for i in mainCoupon {
self.couponsCat.append((mainCoupon[i as! Int] as AnyObject).value(forKey: "category"))
}
for i in coupons {
self.couponsCat.append((coupons[i as! Int] as AnyObject).value(forKey: "category"))
}
for i in mainCoupon {
self.couponsDesc.append((mainCoupon[i as! Int] as AnyObject).value(forKey: “description"))
}
for i in coupons {
self.couponsDesc.append((coupons[i as! Int] as AnyObject).value(forKey: “description"))
}
for i in mainCoupon {
self.couponsTitle.append((mainCoupon[i as! Int] as AnyObject).value(forKey: “name"))
}
for i in coupons {
self.couponsTitle.append((coupons[i as! Int] as AnyObject).value(forKey: “name"))
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell
cell.couponTitle.text = couponsTitle[indexPath.row]
cell.couponDescription.text = couponsDesc[indexPath.row].
cell.couponCategory.text = couponsCat[indexPath.row]
return cell
}
My biggest issue is that I don’t know how to put in a loop the array but with the specification of each section (I mean, the title, description, category, etc.) Any idea?
Rather than having three arrays (one for each property), why not have a custom class for Coupon that has three properties?
class Coupon: AnyObject {
var description: String
var title: String
var category: String
init(description: String, title: String, category: String) {
self.description = description
self.title = title
self.category = category
}
}
If you do it that way, you can avoid so many loops by doing something like this
for coupon in mainCoupon {
let description = mainCoupon["description"]
let title = mainCoupon["name"]
let category = mainCoupon["category"]
let newCoupon = Coupon(description: description, title: title, category: category)
couponsArray.append(newCoupon)
}

Resources