Swift tableViews send array of images to collectionView using parse - arrays

so this is my first post here I've been developing in swift for a few months now and just can't work my way around this problem.
I have tried explaining what I need help with in my image.
If i click on tableview row 1 i want send an array of 30-70 images to a collection view and this kinda works, except it shows same images on all rows, tableview row 2 -3 -4.
image of collectionView
Please take a look at this link for my parse Database
parse database
I am more than happy to share on bitbucket.
//Here goes the TableView
import UIKit
import Parse
class TableViewController: PFQueryTableViewController {
var selectedRow:PFUser?
var userids = [""]
var wonk = ["wonk"]
var slagtHuset = ["slagtHuset"]
var Adelgatan = ["Adelgatan"]
// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
// Configure the PFQueryTableView
self.parseClassName = "crowd"
self.textKey = "cellTitle"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
// self.objectsPerPage = 3
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "crowd")
query.orderByDescending("cellTitle")
// Only retrieve the last ten
query.limit = 10
return query
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomCell")
}
// Extract values from the PFObject to display in the table cell
if let nameEnglish = object?["cellTitle"] as? String {
cell.customNameEnglish.text = nameEnglish
}
// Display flag image
var initialThumbnail = UIImage(named: "question")
cell.customFlag.image = initialThumbnail
if let thumbnail = object?["crowdImage"] as? PFFile {
cell.customFlag.file = thumbnail
cell.customFlag.loadInBackground()
}
return cell
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
var detailScene = segue.destinationViewController as! DetailViewController
// Pass the selected object to the destination view controller.
if let indexPath = self.tableView?.indexPathForSelectedRow {
let row = Int(indexPath.row)
detailScene.currentObject = objects?[row] as? PFObject
//detailScene.currentObject = [Adelgatan, slagtHuset]
// NSIndexPath *indexPath=[self.tableView indexPathForSelectedRow];
// DOG details= (DOG)segue.destinationViewController;
// PFObject *object=[self.typeDog objectAtIndex:indexPath.row ];
// details.stringdata=[object objectForKey:#"username"];
// pass whatever data you want to display in the collection view as an array here.
// details.array = ...
}
}
override func viewDidAppear(animated: Bool) {
// Refresh the table to ensure any data changes are displayed
tableView.reloadData()
}
Here is code for detailView(collectionView)
import UIKit
var countries = PFObject
class DetailViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
// Container to store the view table selected object
var currentObject : PFObject?
var wonk = ["wonk"]
var slagtHuset = ["slagtHuset"]
var Adelgatan = ["Adelgatan"]
// var clubs = [slagtHuset, Adelgatan, wonk]
// Some text fields
#IBOutlet var collectionView: UICollectionView!
#IBOutlet weak var flag: PFImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Resize size of collection view items in grid so that we achieve 3 boxes across
let cellWidth = ((UIScreen.mainScreen().bounds.width) - 3 - 3 ) / 2
let cellHeight = ((UIScreen.mainScreen().bounds.width) - 4 - 3 ) / 2
let cellLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
cellLayout.itemSize = CGSize(width: cellWidth, height: cellHeight)
}
func loadCollectionViewData() {
// Build a parse query object
var query = PFQuery(className:"crowd")
//more specs query.whereKey("currencyCode", equalTo:"EUR")
query.orderByAscending("objectId")
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
// Clear existing country data
countries.removeAll(keepCapacity: true)
// Add country objects to our array
if let objects = objects as? [PFObject] {
countries = Array(objects.generate())
}
// reload our data into the collection view
self.collectionView.reloadData()
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(countries)
return countries.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
// Display "initial" flag image
var initialThumbnail = UIImage(named: "question")
cell.cellImage.image = initialThumbnail
// Here is my problem where i only load image from Adelgatan
// Fetch final flag image - if it exists
if let value = countries[indexPath.row]["Adelgatan"] as? PFFile {
let finalImage = countries[indexPath.row]["Adelgatan"] as? PFFile
finalImage!.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
cell.cellImage.image = UIImage(data:imageData)
}
}
}
}
return cell

Related

Swift - Tableview not updating properly with search queries

I'm using the search bar controller with a tableview. I'm fetching the contacts on my phone to populate the tableview. Here's my code for this part.
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
It retrieves the contact with different phone numbers properly and then displays in the tableview. I've also added multi selection on the tableview to be able to select multiple contacts to continue with my flow of the app.
My issue is when I'm searching for the contact in the search bar , it always gives me the wrong contacts in my tableview. It comes up with the same name always at the top. Returns wrong contact
Now if I print my filteredcontact list , it returns the proper contact that should have been displayed but it is not displayed on the tableview. Here's my code for the search
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
And here's my full class:
class ContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var contactStore = CNContactStore()
var contacts = [ContractStruct]()
var filteredContacts = [ContractStruct]()
var setSelectedItems: Set<Int> = []
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
contactStore.requestAccess(for: .contacts) {(success, error) in
if success {
print("Authorisation Successful")
}
self.fetchContacts()
}
filteredContacts = contacts
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredContacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
}
else {
cell.accessoryType = .none
}
let contactToDisplay = contacts[indexPath.row]
cell.textLabel?.text = contactToDisplay.givenName
cell.detailTextLabel?.text = contactToDisplay.number
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
print(setSelectedItems)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
Just replace contacts[indexPath.row] to filteredContacts[indexPath.row] in cellForRowAt function of tableView delegate.
Because your filtered results stored in filteredContacts and your tableView delegate functions use filteredContacts
I had to replace filteredContacts[indexPath.row] in cellForRowAt for it to work.

Swift Imageview wont load correct image from feed

It appears my loop seems to load all the images taken from a feed into the image view but sets only the very last image from the feed into all cells I'm not sure how to stop this and grab a image for each cell and set it. I'm new to swift and I've sorta jumped right in to programming.. heres the code of interest any help is appreciated
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! BlogPost
let blogPost: BlogPost = blogPosts[indexPath.row]
cell.textLabel?.text = blogPost.postTitle
// cell.textLabel?.text = blogPost.postImageLink
// if cell.postImage?.image == nil {
// let cache = ImageLoadingWithCache()
// cache.getImage(cell.postImageLink, imageView: cell.postImage, defaultImage: "IMG_0079")
if cell.postImage?.image == nil {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// retrieve image from url
let image = UIImage(data: NSData(contentsOfURL: NSURL(string:self.postImageLink)!)!)
self.imageArray.append(image!)
dispatch_async(dispatch_get_main_queue(), { Void in
// set image in main thread
guard indexPath.row < self.imageArray.count else { return }
cell.postImage?.image = self.imageArray[indexPath.row]
})
}
}
blog class
class BlogPost: UITableViewCell {
#IBOutlet weak var postImage: UIImageView!
var postTitle: String = String()
var postLink: String = String()
var postImageLink: String = String()
#IBOutlet weak var postLabel: NSLayoutConstraint!
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

Cannot assign value of type '[[String : AnyObject]]' to type '[[String : AnyObject?]]'

I'm getting the following error:
Cannot assign value of type '[[String : AnyObject]]' to type '[[String : AnyObject?]]'
It's strange this assignment was working before then when I restarted my Xcode, I started to get this error. From what I have read online, this should not give the error.
Here is my code:
import UIKit
import Alamofire
import SwiftyJSON
class Signal Condo TableViewController: UITableViewController {
#IBOutlet var tableview: UITableView!
var singleCondoData = [[String:AnyObject]]()
var CondoIndivi = [[String:AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
self.tableView.delegate = self
self.tableView.dataSource = self
}
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 singleCondoData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SignleTableTableViewCell
if singleCondoData.count != 0 {
let dict = singleCondoData[indexPath.row] as NSDictionary
//cell.label1.text? = (dict["name"] as? String)!
if let nullcheck = (dict["address"] as? String) {
cell.label2.text? = nullcheck
}
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let dict = singleCondoData[indexPath.row] as NSDictionary
if let unitNullCheck = (dict["mls_number"] as? String) {
let item_id = unitNullCheck
getCondoUnits(item_id)
print(item_id)
}
}
//get the individual condo id
func getCondoUnits(condo_id : String){
Alamofire.request(.GET, "http://android.goidx.com/search/?mls_number=" + String(condo_id)).validate().responseJSON { response in
if let value = response.result.value {
let json = JSON(value)
if let resData = json.arrayObject {
self.CondoIndivi = (resData as? [[String:AnyObject]])!
print(self.CondoIndivi)
}
if self.CondoIndivi.count > 0 {
self.tableview.reloadData()
}
}
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "details" :
let buildingdDetailVC = segue.destinationViewController as! DetailsViewController
buildingdDetailVC.CondoIndivi2 = self.CondoIndivi // line of the error
default:
break
}
}
}
}
The type of CondoIndivi2 variable is [[String: AnyObject?]] but you are passing an array of type [[String: AnyObject]] where the dictionary values are non-optional.
Since any non-optional value with same type can be safely converted to its optional corresponding, you can do the following:
buildingdDetailVC.CondoIndivi2 = self.CondoIndivi.map { $0 as [String: AnyObject?] }

Fatal error : Index out of range

I m getting this error :fatal error: Index out of range .I can't get what i m doing wrong .What i'm trying to do is , access an array dictionary by using an integer index than pass a string to get the value mapped to it .The sample works fine on playground but not excode why ? (The array dictionary is not empty)
Here is my code
var CondoIndivi2 = [[String:AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
scrollView.contentSize.height = 1500
print(CondoIndivi2)
if let description_Condo = self.CondoIndivi2[0]["description"] as? String {
print(description_Condo)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is the view that sends data to CondoIndivi2
import UIKit
import Alamofire
import SwiftyJSON
class SignleCondoTableViewController: UITableViewController {
#IBOutlet var tableview: UITableView!
var singleCondoData = [[String:AnyObject]]()
var CondoIndivi = [[String:AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
self.tableView.delegate = self
self.tableView.dataSource = self
}
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 singleCondoData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SignleTableTableViewCell
if singleCondoData.count != 0 {
let dict = singleCondoData[indexPath.row] as NSDictionary
//cell.label1.text? = (dict["name"] as? String)!
if let nullcheck = (dict["address"] as? String) {
cell.label2.text? = nullcheck
}
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let dict = singleCondoData[indexPath.row] as NSDictionary
if let unitNullCheck = (dict["mls_number"] as? String) {
let item_id = unitNullCheck
getCondoUnits(item_id)
print(item_id)
}
}
//get the individual condo id
func getCondoUnits(condo_id : String){
Alamofire.request(.GET, "http://android.goidx.com/search/?mls_number=" + String(condo_id)).validate().responseJSON { response in
if let value = response.result.value {
let json = JSON(value)
if let resData = json.arrayObject {
self.CondoIndivi = resData as! [[String:AnyObject]]
print(self.CondoIndivi)
}
if self.CondoIndivi.count > 0 {
self.tableview.reloadData()
}
}
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "details" :
let buildingdDetailVC = segue.destinationViewController as! DetailsViewController
buildingdDetailVC.CondoIndivi2 = self.CondoIndivi
default:
break
}
}
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
As #James put in his comment, you're creating an empty array in your code:
var CondoIndivi2 = [[String:AnyObject]]()
And then you're trying to access indexing in the position 0:
if let description_Condo = self.CondoIndivi2[0]["description"] as? String {
print(description_Condo)
}
And of course, you will have a runtime error of Index of out Range because your array it's empty, you always need to be sure before index an array that the index is greater than zero, less than equal to the size of the array and the array is not empty.
I hope this help you.
Inside your getCondoUnits(condo_id : String) is an asynchronous block(Alamofire.request), the CondoIndivi2 is received later than the viewDidLoad is executed. You should just pass condo_id to next viewController and do the request in it.

Fatal error: Array index out of range. About a collectionView

The controller has a collectionView, including 1 cell, 5 section and some row, downloading data from LeanCloud just like Parse. Code always fails with fatal error: Array index out of range. In my opinion, I may have some problem in dealing with array of array, about how to access and how to add element. Any one can help me solve this bug? The bug line is listed below:
var temp = self.restaurantLean[number].
import UIKit
import AVOSCloud
class DiscoverViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, RestaurantLeanCollectionCellDelegate, UIGestureRecognizerDelegate {
#IBOutlet var imageView: UIImageView!
#IBOutlet var collectionView: UICollectionView!
private var restaurantLean = [[RestaurantLean]]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = UIColor.clearColor()
loadTripsFromLeanCloud()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: Data Source
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return restaurantLean.count
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return restaurantLean[section].count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! RestaurantLeanCollectionCell
cell.delegate = self
cell.nameLabel.text = restaurantLean[indexPath.section][indexPath.row].name
cell.typeLabel.text = restaurantLean[indexPath.section][indexPath.row].type
cell.locationLabel.text = restaurantLean[indexPath.section][indexPath.row].location
cell.isLike = restaurantLean[indexPath.section][indexPath.row].isLike
cell.imageView.image = UIImage()
cell.layer.cornerRadius = 4.0
if let image = restaurantLean[indexPath.section][indexPath.row].image {
image.getDataInBackgroundWithBlock({ (imageData, error) -> Void in
print(image)
if let data = imageData {
print("loading")
cell.imageView.image = UIImage(data: data)
print("success")
}
})
}
return cell
}
//Download the data from Baas LeanCloud
func loadTripsFromLeanCloud() {
restaurantLean.removeAll(keepCapacity: true)
for number in 0...4 {
let name = "Restaurant_" + String(number)
print(name)
print(number)
let query = AVQuery(className: name)
query.cachePolicy = AVCachePolicy.NetworkElseCache
print("1")
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
print("2")
if let error = error {
print("3")
print("Error: \(error) \(error.userInfo)")
}
print("4")
if let objects = objects {
print("5")
for (index, object) in objects.enumerate() {
let restaurant = RestaurantLean(avObject: object as! AVObject)
self.restaurantLean[number].append(restaurant)
let indexPath = NSIndexPath(forRow: index, inSection: number)
self.collectionView.insertItemsAtIndexPaths([indexPath])
}
}
})
print("6")
}
}
You are not adding elements to restaurantLean array itself (you only add objects to nested arrays). Here is possible solution.
func loadTripsFromLeanCloud() {
restaurantLean.removeAll(keepCapacity: true)
for number in 0...4 {
restaurantLean.append([]) // This line
// ...
}
}

Resources