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
Related
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
}
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...:)
I have an app that takes user inputs in an alertController, and then this values will be stored in CoreData which is then displayed in a tableview. I concatenated all the strings to gather with a comma as separator to make it easier for me to export a csv. However, when I print out the CoreData entity, I get an array that is quite complicated. The array looks like this:
[ (entity: AlarmItems; id: 0xc2bccd37cb753acb ; data: {
alarmAttributes = "Example Name, 24/11/2019, 1500, True, NIL";
}), (entity: AlarmItems; id: 0xc2bccd37cb653acb ; data: {
alarmAttributes = "Example , 12/12/2019, 24/11/2019, True, NIL";
})]
I would like to pull out just that parts after alarmAttributes to be exported into a CSV for further use.
I looked at NSEntityMapping but that did not help me. I'm quite stuck right now. I do not know how to approach the problem. Is my approach even correct in the first place? Is it even possible to export a csv using a an array that I create? The idea is to have the csv be stored in the iOS Device which can then be emailed elsewhere.
My ViewController:
class ViewController: UITableViewController {
var alarmItems: [NSManagedObject] = []
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "AlarmItems")
do {
alarmItems = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}
#objc func addAlarmItem(_ sender: AnyObject) {
print("this works")
let alertController = UIAlertController(title: "Add New Item", message: "Please fill in the blanks", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
//combined string of attributes
let myStrings: [String] = alertController.textFields!.compactMap { $0.text }
let myText = myStrings.joined(separator: ", ")
self.save(myText)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
alertController.addTextField { (textField) in
textField.placeholder = "Enter Name of Engineer"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Date of Alarm in DD/MM/YYYY"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Time of Alarm in 24h (eg: 2300)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Please indicate True/False (type True or False)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Insert comments (if any), or NIL"
}
alertController.addAction(saveAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
func save(_ itemName: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "AlarmItems", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(itemName, forKey: "alarmAttributes")
do {
try managedContext.save()
alarmItems.append(item)
} catch let err as NSError {
print("Failed to save an item", err)
}
}
#objc func exportCSV(_ sender: AnyObject) {
//will work on exporting csv in the future
return
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return alarmItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let alarmItem = alarmItems[indexPath.row]
cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
return cell
}
}
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.
I have a tablecell to work with and I can populate it when I use a written array (like values = [""]) so I know it is working.
But I am using json with swiftyjson to get my info in my table, which is part of a right slideout page I made with mmdrawer. When I println the json output I get all the info I need, but it is not being taken to the table or other variables/arrays.
How do I make this code work?
import UIKit
class RightSideViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var songname = [String]()
var menuImage = [String]()
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBarHidden = true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
getmusiclist()
}
func getmusiclist(){
let search:NSString = "music" as NSString
let url = NSURL(string:"http://xxxxxx/music-manager.php")
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
var request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 2.0)
request.HTTPMethod = "POST"
// set Content-Type in HTTP header
let boundaryConstant = "----------V2ymHFg03esomerandomstuffhbqgZCaKO6jy";
let contentType = "multipart/form-data; boundary=" + boundaryConstant
NSURLProtocol.setProperty(contentType, forKey: "Content-Type", inRequest: request)
// set data
var dataString = "search=\(search)"
let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = requestBodyData
// set content length
//NSURLProtocol.setProperty(requestBodyData.length, forKey: "Content-Length", inRequest: request)
var response: NSURLResponse? = nil
var error: NSError? = nil
let dataReply = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&error)
var results = NSJSONSerialization.JSONObjectWithData(dataReply!, options: nil, error: &error) as! NSDictionary
var jsonOutput = JSON(data: dataReply!)
println(jsonOutput)
let musicListArray = jsonOutput.arrayValue
dispatch_async(dispatch_get_main_queue(), {
for playlist in musicListArray
{
let trackname = playlist["track_name"].stringValue
println("trackName: \(trackname)")
self.songname.append(trackname)
}
/* dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})*/
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return songname.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
var mycell = tableView.dequeueReusableCellWithIdentifier("playerCell", forIndexPath: indexPath) as! MusicTableViewCell
mycell.artistLabel?.text = songname[indexPath.row]
return mycell
}
}
Eventually I would also like to take the name, genre and streaming url and have avplayer play it - will that be something I can add to this code?
the problem with in the part that i forgot to add the uitableview outlet in the uiviewcontroller. I have added it and now the error is gone. I still have to figure out why i am not getting anything but it seems that i am nu getting the data from the jsonOutput.arrayvalue.