Good day.
I am currently using Alamofire version 4.5 and xcode version 9.3. I am trying to load images from URLrequest with custom headers to a collection view with image from a fileserver using this code
var imageRequest = URLRequest(url: URL(string: "myurl here ")!)
imageRequest.addValue(MyVariables.accountToken, forHTTPHeaderField: "accountToken")
imageRequest.addValue("header value 1", forHTTPHeaderField: "header field 1")
imageRequest.addValue("header value 2", forHTTPHeaderField: "header field 2")
imageRequest.addValue(imageurl from fileserver, forHTTPHeaderField: "file")
After adding headers to the urlrequest I use this alamofire responseimage to set value to the image
Alamofire.request(imageURLRequest).responseImage { response in
if let image = response.result.value {
self.count += 1
print("image \(self.count )", image)
} else {
print("unable to load \(self.count)")
}
}
The problem I am encountering is that not all images are loading at once eventhough I have already looped in the alamofire request with the number of urlrequests I have. Another thing, when I scroll the collectionview the photos I have loaded from the alamofire call jumbles in order not following the indexpath.row. Moreover, I have also tried to append the image response from my alamofire response image and set it to
cell.imageView.image = self.imageArray[indexPath.row]
but it goes out of bounds. When I log the the alamofire imageresponse it only loads until index 7. I have tried different approach like appending the urlrequest to array and loading it to collection view cell via
cell.imageView.af_setImage(withURLRequest: imageURLRquest)
but it only loads the first item in the image array. Sorry for the long question as I have tried most of the solutions I have found so far but it doesnt fix the problem I have right now. Please provide suggestions to fix this. Thank you in advance.
UPDATE:
Here is the code for the datasource from alamofire request. It returns 10 urlrequest that is being appended to the array
var imageRequest = URLRequest(url: URL(string: "myurl here ")!)
imageRequest.addValue(MyVariables.accountToken, forHTTPHeaderField: "accountToken")
imageRequest.addValue("header value 1", forHTTPHeaderField: "header field 1")
imageRequest.addValue("header value 2", forHTTPHeaderField: "header field 2")
imageRequest.addValue(imageurl from fileserver, forHTTPHeaderField: "file")
self.imageArray.append(imageRequest)
This is for the cellForItemAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BooksCell", for: indexPath) as! LibraryCollectionViewCell
cell.imageView.af_setImage(withURLRequest: self.imageArray[indexPath.row])
cell.bookName.text = self.booksObject[indexPath.row].object(forKey: "title") as! String
cell.cosmosRatingView.rating = self.booksObject[indexPath.row].object(forKey: "rating") as! Double
return cell
}
Good day. I have already found the solution for this. You would need to reset the value of the imageView to nil at cellForItemAt then assign it to the indexPath.row
if let image = self.bookImages[indexPath.row] {
cell.imageView.image = image
} else {
Alamofire.request(imageURLRequest).responseImage { response in
if let image = response.result.value {
cell.imageView.image = image
self.bookImages[indexPath.row] = image
} else {
cell.imageView.image = placeholderImage
}
}
}
Thank you for all your help. Hope this also helps someone who encountered the same problem.
You have error at self.imageArray[indexPath.row] will crash with index goes out of bounds because number of items in cell will be equal to self.booksObject.count-1 what if self.booksObject is greater than image array ?!
so you have to make sure that self.imageArray.count = self.booksObject.count
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.booksObject.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BooksCell", for: indexPath) as! LibraryCollectionViewCell
cell.imageView.af_setImage(withURLRequest: self.imageArray[indexPath.row])
cell.bookName.text = self.booksObject[indexPath.row].object(forKey: "title") as! String
cell.cosmosRatingView.rating = self.booksObject[indexPath.row].object(forKey: "rating") as! Double
return cell
}
Related
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateCollectionViewCell", for: indexPath) as! DateCollectionViewCell
//Calendar as I have changed the resuse Identifer.
cell.backgroundColor = UIColor.white
cell.DateLabel.textColor = UIColor.black
cell.dateSubTitle.text = "500"
monthsforselect()
// self.newday = ["\(year)\\/\(cm)\\/\(indexPath.row - PositionIndex + 1)"]
newday = "\(year)\\/\(cm)\\/\(indexPath.row - PositionIndex + 1)"
// print(newday)
// print(ele, element)
// if newday == "2018\\/03\\/29"{
// cell.dateSubTitle.text = "GOOD"
// }
This is my cellForItemAt and I am trying to pass value in Cell.DateSubtitle.text from an array. Below are the array contains two array. self.date_listArray and self.actual_balanceArray. New day is the string which contains my calendar date. Below that I have date_subtitle label to pass some value on proper date I want to check the value if date that is coming from "New day" array Above cell for item In self.date_listArray and it matches change the cell.dateSubtitle.text with value in self.actual_balanceArray and if not matched pass "" (empty string ). This is my code for for loopenter image description here Please do check the image link below and I have also check with passing one string and it works fine but not able to check with array. Thanks in advance to friend!
for element in self.actual_balanceArray{
// print("elemenst: \(element)")
}
for ele in self.date_listArray{
if self.date_listArray.contains("\(self.newday)"){
print(self.date_listArray.index(of: self.newday))
}
}
You can find if String contains the Value from the array like:
let arrDate = ["2018/04/01", "2018/04/04", "2018/04/04", "2018/04/08"]
let newdayString = "(2018/04/01 2018/04/02 2018/04/03 2018/04/04 2018/04/05 2018/04/06 2018/04/07 2018/04/08)"
for date in arrDate{
if newdayString.range(of:date) != nil {
print("string Present")
}else{
print("not present")
}
}
Hope this Help!
Please check this I am not allowed to comment any more//
this is from view did load
do {
Alamofire.request("my api link", method: .post, parameters: parameters).responseJSON
{(response) in
if let json = response.result.value as NSDictionary{
self.data_Array = json.value(forKey: "Data") as! NSArray
self.date_listArray = self.data_Array.value(forKey: "date_list") as! NSArray
}catch{
print("error")
}
This is my cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateCollectionViewCell", for: indexPath) as! DateCollectionViewCell
print(self.date_listArray)
//the above print gives me empty string
}
I am stuck in my code, I am trying show to API response tableview cell but i have not any idea how to fill data in array ,So not showing anything in my tableviewcell. I am using custome cell and Alamofire in swift. Please improve my mistake give me solution .
func Api_call()
{
let url = URL(string: "https://dousic.com/api/radiolist")!
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
// let fragment = components.fragment!
print(components)
let params = ["user_id":"16" ]
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default).responseJSON {response in
self.hideActivityIndicator()
var err:Error?
switch response.result {
case .success(let value):
print(value)
let json = JSON(value)
// returns nil if it's not an array
if let resData = json["radioList"].arrayObject
{
self.array_RadioList = resData as! [[String:AnyObject]]
}
if self.array_RadioList.count > 0 {
self.tbl_home.reloadData()
}
case .failure(let error):
err = error
print(err ?? "error .....")
}
}
}`
Thanks for help .
EDIT
Just create a radio list variable like this
var array_RadioList:[JSON]?
Get array from json like this
-
if let resData = json["response"]["radioList"].array {
self.array_RadioList = resData
self.tableView.reloadData()
}
and reload data.And get radio object in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell? = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier)
let radio:JSON? = array_RadioList?[indexPath.row]
cell?.textLabel?.text = radio?["radio_tags"].string
return cell ?? UITableViewCell()
}
If you are getting your array_RadioList from Api_call(), try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : homeCell = tableView.dequeueReusableCell(withIdentifier: "homeCell")! as! homeCell
cell.lbl_name?.text = array_RadioList[indexPath.row]["radio_title"] as? String
return cell
}
and also check for numberOfRowsInSection function.
If the API you're calling is well-made, you should use a get method, not a post.
Also, I tried to use "https://dousic.com/api/radiolist?user_id=16" but it return
{
"response": {
"code": "301",
"error": "wrong url"
}
}
These 2 things could be your problem, or it could be in your custom cells, or in you cellforrow method...
If you can show more code it would help.
EDIT
Try to use this version of the optional chaining :
if let resData = json["radioList"].arrayObject as? [[String:AnyObject] {
self.array_RadioList = resData
self.tbl_home.reloadData()
}
and try to debug it with breakpoints to see if the application goes everywhere you want and what are your variables at this time.
Try this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return [self.array_RadioList].count;
}
I want to grab images from an api which gives the url of the image, do i need another api call to download the images from their url's? How do i grab every image and append it in an array and display them in my collection view cell. I have declared this outside the class scope
var videoArray = [funnyVideos]()
Alamofire.request(_url).responseJSON { (response) in
print(response.result.value!)
if let dict = response.result.value as? Dictionary<String, AnyObject> {
if let result = dict["result"] as? Dictionary<String, AnyObject> {
if let data = result["data"] as? [Dictionary<String, AnyObject>] {
for obj in data {
let mainObj = funnyVideos()
mainObj.parseData(from: obj)
videoArray.append(mainObj)
// print (obj)
}
if let image1 = data[0]["image"] as? String {
print(image1)
}
self.collection.reloadData()
}
}
}
completed()
}
this function is another class: funny videos
func parseData(from: Dictionary<String, AnyObject>){
if let name = from["title"] as? String{
self._name = name.capitalized
}
}
this func configure cell is another class which holds the outlets for the label and imageview of collection cell.
func configureCell(_ funny : funnyVideos) {
self.funny = funny
nameLabel.text = self.funny.name.capitalized
// imageView.image = UIImage()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
fun = videoArray[indexPath.row]
cell.configureCell(fun)
}
what options do I have here to grab them from a url in the UIImage container? and print(image1) prints the url of the image.
Try it,
You can use AlamofireImage for downloading image and set to the collectionview.
Yes, you have to make another api call on image's url. You can use AlamofireImage or sdwebimage library for download images.
First hit Api with normal Alamofire library and get link of all images and save them in dict or array . Then make another api call using AlamofireImage or sdwebimage.
you should try sdwebimage becauz it is easy
You should use a Swift library called Kingfisher
It will handle caching as well as downloading of the images when you provide the URLs.
Here is the link for getting started. Cheat Sheet
Yes you need to call the url of images that fetch from json, to get image from url you can either use
use like this
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let identifier = cellIdentifier else{
fatalError("Cell identifier not provided")
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier ,
for: indexPath) as UICollectionViewCell
let imageUrl = arrayImage[indexPath.row]
cell.imageView.setImage(url:"imageUrl")
return cell
}
https://github.com/rs/SDWebImage
https://github.com/onevcat/Kingfisher
I was trying to make a wallpaper app and my code was working all fine when I had the entire implementation in the ViewController file. And then I shifted some of the code to another class. Here is the code.
ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
photoOperations.getStuffFromJson()
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoOperations.previewUrlArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CollectionViewCell
cell.backgroundColor = UIColor.whiteColor()
if let img = self.images[indexPath] {
cell.imageView.image = img
} else {
photoOperations.downloadThumbnail(indexPath.row){ (image) in
dispatch_async(dispatch_get_main_queue()) {
if let img = image {
cell.imageView.image = img
self.images[indexPath] = img
} else {
print("Images will be loaded in a few seconds!")
}
}
}
}
return cell
}
PhotoOperations.swift
func getStuffFromJson( ){
Alamofire.request(.GET, "https://example.com/api/", parameters: ["key": "123.."])
.responseJSON{ response in
if let value = response.result.value {
let hits = JSON(value)["hits"]
var counter = 0
while counter < hits.count {
if let previewString = hits[counter]["previewURL"].rawString(){
self.previewURL = NSURL(string: previewString)!
self.previewUrlArray.append(self.previewURL!)
counter += 1
} else{ print("Error : A previewURL wasn't found.")
}}}}}
func downloadThumbnail(forIndexPathAtRow : Int , completion: (UIImage?)->Void) {
if previewUrlArray.count > 0 {
... // create URL task , session etc.
}
}
How do I reload the data in the ViewController? I tried adding a collectionView parameter to the getStuffFromJSON method and calling collectionView.reload at the end. But that doesn't work. Also I get 0 as previewURLArray.count in the numberOfItemsInSection method.
Did you try to set images out of the dispatch_async and reloadData() method into the dispatch_async ?
I have developed basic similar app which works with Alamofire Pod .
In download / fetch function used the settings works than later in a dispatch block called the reloadData() of my tableView
There is a one difference , i worked with tableView , your app works with collectionView
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData();
})
A small part of my app
//user reference
let user : User = User()
//dictionary , contains json datas
user.setValuesForKeysWithDictionary(dictionary);
tableView works with users , String array . Before the dispatch_async
append user to it then call reloadData() in the async
Then
self.users.append(user);
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData();
})
Im using AlamofireImage to load images in an async way.
It works quite well except when I scroll very fast the app crashes.
I assume it is because when maybe more than 10 requests are being sent in a very short period of time the app crashes (when I scroll fast).
I also see a sudden spike in memory usage.
When I scroll slowly and maybe 4 requests are sent in a short period it does not crash.
Does anyone have a hint on how to prevent this? How can I cancel requests of invisible cells where the user has been scrolled by?
Here is the code:
// Dequeue your cell and other code goes here.
// with as! the cell is set to the custom cell class: DemoCell
// afterwards all data can be loaded from the JSON response into the cells
override func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("FoldingCell",
forIndexPath: indexPath) as! DemoCell
cell.delegate = self
//tag the cell with the indexpath row number to make sure the loaded asynch image corresponds to the right cell
cell.tag = indexPath.row
//clear cell of eventually reused images
cell.schoolCoverImage.image = UIImage()
cell.schoolBiggerImage.image = UIImage()
//TODO: set all custom cell properties here (retrieve JSON and set in cell), use indexPath.row as arraypointer
let resultList = self.items["result"] as! [[String: AnyObject]]
let itemForThisRow = resultList[indexPath.row]
cell.schoolNameClosedCell.text = itemForThisRow["name"] as! String
cell.schoolNameOpenedCell.text = itemForThisRow["name"] as! String
self.schoolIdHelperField = itemForThisRow["name"] as! String
cell.schoolIntroText.text = itemForThisRow["name"] as! String
// set the button's tag like below.
cell.innerCellButton.tag = indexPath.row
//call method when button inside cell is tapped
cell.innerCellButton.addTarget(self, action: #selector(MainTableViewController.cellButtonTapped(_:)), forControlEvents: .TouchUpInside)
cell.schoolIntroText.text = "We from xx University..."
//handle the image from a separate API call
let schoolIdNumber = itemForThisRow["sco_id"] as! NSInteger
let schoolIdString = String(schoolIdNumber)
//TOCHeck: maybe Id is not correct and should be replaced by indexCount
let imageNameString = itemForThisRow["image"] as! String
//only load the image of the cell which is visible in the screen
// print("current cells visible?")
// print(tableView.visibleCells)
// print("currentCell")
// print(cell.tag)
// if(tableView.visibleCells.contains(cell)) {
let urlRequest = NSURLRequest(URL: NSURL(string: "https://ol-web- test.herokuapp.com/olweb/api/v1/schools/"+schoolIdString+"/image/"+imageNameString)!)
print(urlRequest)
//does cell number/tag match current indexpath row?
if(cell.tag == indexPath.row) {
//use cache in case image has been saved to cache already, otherwise get image from networking
if(self.photoCache.imageForRequest(urlRequest) != nil) {
cell.schoolCoverImage.image = photoCache.imageForRequest(urlRequest)
cell.schoolBiggerImage.image = photoCache.imageForRequest(urlRequest)
print("image from cache loaded")
}
else
{
self.imageDownloader.downloadImage(URLRequest: urlRequest) { response in
print(response.request)
print(response.response)
debugPrint(response.result)
if let image = response.result.value {
print("here comes the printed image:: ")
print(image)
print(schoolIdString)
//set image to the cell
cell.schoolCoverImage.image = image
cell.schoolBiggerImage.image = image
self.photoCache.addImage(image, forRequest: urlRequest)
print("image from network loaded and added to cache")
print(self.photoCache.memoryCapacity.description)
print(self.photoCache.memoryUsage.description)
}
}
}
}
return cell
}
EDIT: Log error is a NullPointer
30/image/Beet_Language_Bournemouth_1.jpeg }
fatal error: unexpectedly found nil while unwrapping an Optional va lue
Code line:
let urlRequest = NSURLRequest(URL: NSURL(string: "https://ol-web- test.herokuapp.com/olweb/api/v1/schools/"+schoolIdString+"/image/"+imageNameString)!)
I load here the params schoolIdString and imageNameString from a previous query.
Thx for the answers. It was corrupt data from the database which made the URL corrupt