UICollectionView error when using SDWebImage - arrays

I used SDWebImage and cell.Food.sd_setImage(with: URL(string: foodImage[indexPath.row])) to display the images and foodImage array contains the URL.
When I run it and got errors as below. I have no idea how to fix it and I can't found any errors about that. Does anyone know how to fix it? thanks.
Task <D58DD2B3-88A0-4673-BF27-A7AC5A65F3B4>.<3> finished with error - code: -999
...
Task <340CEBFF-ADE8-4C07-851D-0BD1F0159F20>.<8> finished with error - code: -999
Failed to get TCPIOConnection in addInputHandler
Task <5C16CD7B-2234-4BB6-BE2A-0D71ECD35658>.<12> finished with error - code: -999
[] nw_endpoint_flow_attach_protocols_block_invoke [4.1 107.20.173.119:443 in_progress socket-flow(satisfied)] Failed to attach application protocol CFNetworkConnection
Here is my code:
class MainPageController: UIViewController, UICollectionViewDelegate,UICollectionViewDataSource{
public var foodTitle = [String]()
public var foodImage = [String]()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
collectionView.dataSource = self
collectionView.delegate = self
DispatchQueue.main.async {
collectionView.reloadData()
}
return foodImage.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MainPageCollectionViewCell
cell.FoodTitle.text = self.foodTitle[indexPath.item]
cell.Food.sd_setImage(with: URL(string: foodImage[indexPath.row]),placeholderImage: UIImage(named: "image")) // I tried your suggestion but it still failed.
return cell
}
extension MainPageController{
public func fetchFoodList(){
let url = URL(string: "https://api.edamam.com/search?q=egg&app_id=110d8671&app_key=3f01522208d512f592625dfcd163ff5c&from=0&to=10")
let task = URLSession.shared.dataTask(with: url!){ (data, response, error) in
if error != nil{
print(error!)
}else{
if let urlContent = data{
do{
let json = try JSON(data:data!)
let recipes = json["hits"]
self.foodTitle=json["hits"].arrayValue.map{$0["recipe"]["label"].stringValue}
print(self.foodTitle)
self.foodImage = json["hits"].arrayValue.map {$0["recipe"]["image"].stringValue}
print(self.foodImage)
}
catch{
print("JSON Processing Failed")
}
}
}
}
task.resume()}}

i'm using sd_WebImage and it's working for me with following code :-
import SDWebImage
func collectionView(_ collectionView: UICollectionView, cellForItemAt
indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell",
for: indexPath) as! stackCollectionViewCell
cell.imageview.sd_setImage(with: URL(string: imageArr[indexPath.row]),
placeholderImage: UIImage(named: "image"))
return cell
}
But your error is for Thread because something is interrupting the main thread that's why this error is appear. so can you share your code.
Thanks

Related

Swift ios Kanna data returning empty first time in viewDidLoad

I am trying to load data from an API into my TableViewController but the first time it loads the data returns empty. I can't build a table because the data is empty.
import UIKit
import Kanna
class TableViewController: UITableViewController {
var country = [String]()
override func viewDidLoad() {
super.viewDidLoad()
gets()
print(country)// is empty view controller.
}
func gets(){
let url = "https://site"
let myURL = NSURL(string: url)
let URLTask = URLSession.shared.dataTask(with: myURL! as URL) {
myData, response, error in
guard error == nil else {return}
let myHTML = String(data: myData!, encoding: String.Encoding.utf8)
DispatchQueue.global(qos: .userInitiated).async {
if let doc = try? HTML(html: myHTML!, encoding: .utf8) {
DispatchQueue.main.async {
for fdata in doc.xpath("//*[#id='content']/table[3]") {
let i = fdata.text!
self.country.append(i)
}
}
}
}
}
URLTask.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return country.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = country[indexPath.row]
return cell
}
I know that there are many similar problems. I tried different options but I didn't succeed.
Since the data is coming from a network request, the table will always be empty initially. You could fetch the data from the previous view controller (displaying some kind of loading indicator) and wait to present this one until the fetch has completed.
Or, if you are just looking to reload your table when the data comes in, try adding a self.tableView.reloadData() after the data has loaded:
...
DispatchQueue.main.async {
for fdata in doc.xpath("//*[#id='content']/table[3]") {
let i = fdata.text!
self.country.append(i)
}
self.tableView.reloadData()
}
...
Found it! Use the viewWillAppear (_animated: Bool) method that is called before the view appears on the screen.
override func viewWillAppear(_ animated: Bool) {
gets()
}

URL array throwing optional error swift

I am not sure how to resolve the optional type error that occurs at "if let imageURL = imageFile.path" in my code below. The error it throws is "Initializer for conditional binding must have Optional type, not 'String'"
After googling, I'm guessing it has something to do with the directoryContentsArray = URL I set at the beginning of my CollectionViewController class.
Please help!
P.S. Sorry for the repeat optional error question, but I'm super confused :/
class CollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var directoryContentsArray = [URL]()
fileprivate let itemsPerRow: CGFloat = 3
fileprivate let sectionInsets = UIEdgeInsets(top: 50.0, left: 20.0, bottom: 50.0, right: 20.0)
#IBOutlet weak var collectionView: UICollectionView! { didSet {
collectionView.delegate = self
collectionView.dataSource = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
func fetchDirectoryContents() {
let fileManager = FileManager.default
let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)
self.directoryContentsArray = directoryContents
self.collectionView.reloadData()
}
checkPhotoLibraryPermission()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.collectionView.reloadData()
}
//number of views
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return directoryContentsArray.count
}
//populate the views
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? myCell {
let imageFile = self.directoryContentsArray[indexPath.item]
if let imageURL = imageFile.path,
imageFile.pathExtension == "jpeg",
let image = UIImage(contentsOfFile: imageURL) {
cell.myImageView.image = image
} else {
fatalError("Can't create image from file \(imageFile)")
}
return cell
}
return UICollectionViewCell()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imageURL = info[UIImagePickerControllerImageURL] as? URL {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
try FileManager.default.moveItem(at: imageURL.standardizedFileURL, to: documentDirectory.appendingPathComponent(imageURL.lastPathComponent))
collectionView.reloadData()
} catch {
print(error)
}
}
picker.dismiss(animated: true, completion: nil)
}
Thanks again!
The definition of the path property of URL is:
var path: String
So it doesn't return an optional which means you don't need to do the let assignment.
Just change to this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? myCell {
let imageFile = self.directoryContentsArray[indexPath.item]
if imageFile.pathExtension == "jpeg",
let image = UIImage(contentsOfFile: imageFile.path) {
cell.myImageView.image = image
} else {
fatalError("Can't create image from file \(imageFile)")
}
return cell
}
return UICollectionViewCell()
}

append 2 arrays in a collection view

So I have 2 arrays, 1 being a photoPost array and the other a videoPost array. Now is it possible to display both these arrays in the one collection view at the same time? I tried to use the method below but does not work out. I'm not sure if I'm even doing it right.Much help would be appreciated. Thanks in advance
var photoPosts = [photoPost]()
var videoPosts = [videoPost]()
func retrieveData(){
let ref = Database.database().reference().child("videoPost").child(uid)
ref.observe(.childAdded, with: { (snapshot) in
let dictionary = videoPost(snapshot: snapshot)
self.videoPosts.append(dictionary)
})
let ref = Database.database().reference().child(“photoPost").child(uid)
ref.observe(.childAdded, with: { (snapshot) in
let dictionary = photoPost(snapshot: snapshot)
self. photoPosts.append(dictionary)
})
self.newsfeedCollectionView?.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return videoPosts.count + photoPosts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! newsfeedCollectionViewCell
cell. photoPost = photoPosts[indexPath.item]
cell.videoPost = videoPosts[indexPath.item] // fatal error:index out of range
return cell
}
Please Try this
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! newsfeedCollectionViewCell
if indexPath.item < photoPosts.count {
cell. photoPost = photoPosts[indexPath.item]
} else {
cell.videoPost = videoPosts[indexPath.item-photoPosts.count]
}
return cell
}

Swift: How can I get the records from the database according to the cell pressed

Is it possible to get the data from the external database when a UItableViewCell is pressed?
I managed to create a UItableView where I am displaying the data from the database. If I press a cell then all the data that are linked to it should be displayed. For eg. if I have 4 main categories in the database such as TOOLS, OTHERS, SECURITY, PETS and each of them has its sub-catecory and are linked with each other in the database. So if I click on Pets, it should filter out and only Show me CATS, DOGS, COWS, LIONS. When I run this SQL I am able to get the information but cant figure it this out on Swift.
UItableViewCell is in my FirstviewController and its the Main Category .
When I click here it goes to my destination VC and has the table again in here.enter image description here
DestViewController is the sub-category
enter image description here
My CategoryList_ViewController.swift
import Foundation
import UIKit
import WebKit
class CategoryList_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let url = NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\cat.php")
let data = NSData(contentsOfURL: url!)
values = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CategoryList_TableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "catView" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let value = values[indexPath.row]
let controller = segue.destinationViewController as! SubCatergory_ViewController
controller.cate_Id = value["id"] as! String
controller.catTitleRec = value["NAME"] as! String
}
}
}
}
my SubCatergory_ViewController.swift
import Foundation
import UIKit
import WebKit
class SubCatergory_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var caID: UILabel!
#IBOutlet weak var catTitle_Label: UILabel!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
var catTitleRec = ""
var cate_Id = ""
override func viewDidLoad() {
super.viewDidLoad()
catTitle_Label.text = catTitleRec
caID.text = cate_Id
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let request = NSMutableURLRequest(URL: NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\subcat.php")!)
request.HTTPMethod = "GET"
let postString = "a=\(cate_Id)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! subCateListTableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
}
and my subcat.php
<?php
$connection = mysql_connect(........);
$catefilter = $_GET['a'];
if(!$connection){
die('Connection Failed');
}
else{
$dbconnect = #mysql_select_db($database_UNIASSIGNMENT, $connection);
if(!$dbconnect){
die('Could not connect to Database');
}
else{
$query = 'SELECT category_group.group_id , category.NAME FROM category_group LEFT JOIN category ON category.id = category_group.category_id WHERE category_group.group_id =' . $catefilter ;
$resultset = mysql_query($query, $connection);
$records= array();
while($r = mysql_fetch_assoc($resultset)){
$records[] = $r;
}
echo json_encode($records);
}
}
?>
My first VC works fine but my second VC doesnot get the data
Thanks for your time :)
SK
To access the cell that has been pressed, you need to call the didSelectRowAtIndexPath function.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let value = values[indexPath.row]
let vc = storyboard?.instantiateViewController(withIdentifier: "SubCatergory_ViewController") as! SubCatergory_ViewController
vc.cate_Id = value["NAME"] as! String
//self.navigationController?.pushViewController(vc, animated: true)
self.present(vc, animated: true, completion: nil)
}
First you get the value out of your values Array on the indexPark.row. Then you instantiate your second viewController.
Then you set your String value of cate_Id to the desired String value of your item value. And then you just need to present the new viewController.
If you're using a UINavigationController and you want a "back" button, then you use: self.navigationController?.pushViewController(vc, animated: true)
If you just want to present the viewController, you use self.present(vc, animated: true, completion: nil)
Comment or uncomment whatever presentation method you prefer.

Swift: Array of audio files

Using Swift 2 how would I create an array of audio files to be used on a collection view?
There are 4 options "Ocean", "Birds", "Nature", "Waves" and they are displayed as cells.
When a cell is clicked, I need it to play the sound. Can you please help?
var imageArray = [UIImage(named: "ocean"),UIImage(named: "birds"),UIImage(named: "nature"),UIImage(named: "wave")]
var nameArray = ["Ocean","Birds","Nature","Waves"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! homeCollectionViewCell
cell.iconImage?.image = imageArray[indexPath.item!]
cell.label.text = nameArray[indexPath.item!]
return cell
}
Do you know how to play the sound? Have you done it yet?
If so, you need to use the following function and do something like this:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
//grab the sound from the array
let sound = your_array_with_sounds[indexPath.row]
//if you want to play the sound in this view:
<code to play the sound>
//if you want to play the sound in another view:
<perform the segue and pass the sound to the view you want>
}
I hope this help. If not, add a bit more of information to your question and we will help you.
You need to use the AVAudioPlayer Class for Play the Audio
For that you need to import the below class
import AVFoundation
you need to create the function with Following code
let audioName:String!
func playAudio(){
let url = NSURL.fileURLWithPath(
NSBundle.mainBundle().pathForResource(audioName,
ofType: "mp3")!)
var error: NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
if let err = error {
println("audioPlayer error \(err.localizedDescription)")
} else {
audioPlayer?.delegate = self
audioPlayer?.prepareToPlay()
}
if let player = audioPlayer {
player.play()
}
}
in collection View
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
audioName = arrayName[indexPath.row]
}
Swift 4.0
let audioName:String!
func playAudio(){
let url = NSURL.fileURL(
withPath: Bundle.main.path(forResource: audioName,
ofType: "mp3")!)
var error: NSError?
let audioPlayer = try? AVAudioPlayer(contentsOf: url)
audioPlayer?.delegate = self
audioPlayer?.prepareToPlay()
if let player = audioPlayer {
player.play()
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
audioName = arrayName[indexPath.row]
}

Resources