Swift: Bool if true, doesn't display image - swift

I'm a beginner so please be patient explaining, Thanks.
So, basically I have a bool column in parse and I want to display an image if it's false and don't display anything if its true.
here are my codes:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("todayCell", forIndexPath: indexPath) as! reqTodaysCell
let cellDataParse: PFObject = self.dataparse.objectAtIndex(indexPath.row) as! PFObject
var newReadQuery = PFQuery(className: "request")
newReadQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
if object["reqRead"] as! Bool == true {
myCell.isRead.image = nil //here is where I say pic to be nil but what happens is that if the first one is true then it will remove the pic for all of them.
// and if its not true it should display the pic
} else {
myCell.isRead.image = UIImage(named: "newReq")
print("user not read")
}
}
}
})
If I don't explain properly please let me know and I will try my best to explain again.

This sounds like an ideal use case for a ternary operator. As per my example below, you use the ? : syntax following a Bool, if the bool is true it will return the first case and if it's false it will return the second case.
newReadQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
let reqRead = object["reqRead"] as! Bool
cell.image.image = reqRead ? nil : UIImage(named: "newReq")
}
}
})
UPDATE
The above may not have worked as the Parse call might not be completed before the cells are loaded.
Create a global variable (outside of any function):
var reqRead = [Bool]()
In ViewDidLoad you can create an array of the bools.
var newReadQuery = PFQuery(className: "request")
newReadQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
reqRead.append(object["reqRead"] as! Bool)
}
tableView.reloadData()
}
})
Then in your CellForRow:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("todayCell", forIndexPath: indexPath) as! reqTodaysCell
let cellDataParse: PFObject = self.dataparse.objectAtIndex(indexPath.row) as! PFObject
cell.image.image = reqRead[indexPath.row] ? nil : UIImage(named: "newReq")
return cell
}
There's a possibility that it will try to populate the cells before the array is loaded but let me know if this works for you.

if object["reqRead"] as! Bool == false {
myCell.isRead.image = nil
myCell.isRead.hidden = false
} else {
myCell.isRead.hidden = true
}

Related

Save & Retrieve TableViewCell checkmark using NSUserDefaults in Swift

I am trying to save and retrieve tableViewCell checkmark using NSUserDefaults.My partial code as below.From the code,I can able to select or deselect cell using UITableViewCellAccessoryType.I am not familiar using NSUserDefaults in Swift.Please,someone point me the direction...
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.allowsMultipleSelection = true
let userDefaults = NSUserDefaults.standardUserDefaults()
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.None
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath)
cell.textLabel!.text = myItems[indexPath.row] as? String
cell.selectionStyle = .None
cell.tintColor = UIColor.greenColor()
return cell
}
Thanks in Advance.
First of all create a class Item as data source with a name and selected property.
class Item {
let name : String
var selected = false
init(name: String) {
self.name = name
}
}
Declare the data source array
var myItems = [Item]()
Create the items this way
let item = Item(name:"Foo") // your former string value, `selected` is false by default.
myItems.append(item)
In applicationDidFinishLaunching register an empty string array as default value for key selectedCells
let defaults = NSUserDefaults.standardUserDefaults()
let defaultValues = ["selectedCells" : [String]()]
defaults.registerDefaults(defaultValues)
To read all selected cells from user defaults get the string array and set the property selected of all corresponding items to true. Then reload the table view. The forced unwrapping is safe because the key/value is pre-registered and always non-optional. Important: Make sure that readDefaults() is always called after registering the default values.
func readDefaults()
{
let defaults = NSUserDefaults.standardUserDefaults()
let selectedItems = defaults.stringArrayForKey("selectedCells")!
for item in myItems {
item.selected = selectedItems.contains(item.name)
}
tableView.reloadData()
}
In cellForRowAtIndexPath set both properties accordingly
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath)
let item = myItems[indexPath.row]
cell.textLabel!.text = item.name
cell.accessoryType = item.selected ? .Checkmark : .None
cell.selectionStyle = .None
cell.tintColor = UIColor.greenColor()
return cell
}
To save the data filter all items whose selected property is true, map it to the names and save the array.
func saveDefaults() {
let selectedCells = myItems.filter { $0.selected }.map { $0.name }
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(selectedCells, forKey:"selectedCells")
}
Now you should change the model in didSelectRowAtIndexPath and reload the row. This is much more efficient (and recommended) than manipulating the cell
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let item = myItems[indexPath.row]
item.selected = true
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}
My example, i Load in tableView set in DetailController
Model ----
struct TheoryData {
var id: String
var theoryText: String
var theoryModes: String
var theoryImage: String
var like: Bool
}
Read values
var theoryData = [TheoryData]()
private func readDefaults() {
let defaults = UserDefaults.standard
let selectedItems = defaults.stringArray(forKey: "selectedCells") ?? []
(0..<theoryData.count).forEach { i in
theoryData[i].like = selectedItems.contains(theoryData[i].id)
}
menuTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
readDefaults()
}
In cell
let theory = theoryData[indexPath.row]
cell.likeImage.image = theory.like ? #imageLiteral(resourceName: "heart-icon") : #imageLiteral(resourceName: "heart-empty-icon")
Save state in UserDefault
#IBAction func likeButtonTapped(_ sender: UIButton) {
theoryData.like.toggle()
let likeIcon = theoryData.like ? #imageLiteral(resourceName: "heart-icon") : #imageLiteral(resourceName: "heart-empty-icon")
likeButton.setImage(likeIcon, for: .normal)
saveSelection()
}
private func saveSelection() {
let defaults = UserDefaults.standard
var selectedItems = defaults.stringArray(forKey: "selectedCell") ?? []
if theoryData.like {
selectedItems.append(theoryData.id)
} else {
selectedItems = selectedItems.filter{ $0 != theoryData.id }
}
print(selectedItems)
defaults.setValue(selectedItems, forKey: "selectedCell")
}
}

How do I get the value from the model to the controller

This is my first program using MVC design pattern, I'm stuck how to get the values from the model to my controller and to display it in my view. I'll show you what I have done. Kindly clarify me what I did wrong? Or show me how it can be done in other way around.
Model
class songData: NSObject {
var artistName: String
var albumName: String
init(artistName: String, albumName: String) {
self.artistName = artistName
self.albumName = albumName
}
}
Controller
#IBAction func doTheSearch(sender: AnyObject) {
itunesAPI().itunesSearch({(song : songData) in
})
self.tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return song1.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = itunesAPI().array[indexPath.row]
cell.textLabel?.text =
cell.detailTextLabel?.text =
return cell
}
API
func itunesSearch(completionHandler:(songData)->()) {
Alamofire.request(.GET, "http://itunes.apple.com/search?", parameters: ["term" : "tamil new songs", "media" : "music"])
.responseJSON { (response) in
let json = JSON(response.result.value!)
if let jsonData = json["results"].arrayObject {
self.array = jsonData as! [[String : AnyObject]]
if self.array.count > 0 {
// self.array = jsonData as! [[String : AnyObject]]
// if let resultsDict = resultsArray.first {
let albumName = json["results"]["collectionName"].stringValue
let artistName = json["results"]["artistName"].stringValue
let song = songData(artistName: artistName, albumName: albumName)
completionHandler(song)
}
}
I do have the nothing on my view except the story board which consists of a table view with a single cell. I need to get the response from the API and show it in the view.
First, you're going to want to reload your table after the data is returned. Update your IBAction to this:
itunesAPI().itunesSearch({(song : songData) in
self.tableView.reloadData()
})
Otherwise reloadData will get called before the data is returned. Set a property on the viewController to house the data. Also, it's good practice to start a class name with a capital letter.
var tableData:[SongData] = [SongData]()
Then set this variable when the data successfully returns:
itunesAPI().itunesSearch({(song : songData) in
self.tableData.append(song) // add the result to the list of data
self.tableView.reloadData() // reload the table
})
Then set the cells as so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = self.tableData[indexPath.row]
cell.textLabel?.text = artistAndAlbum.artistName
cell.detailTextLabel?.text = artistAndAlbum.albumName
return cell
}

UITableView in swift

can anyone tell me what's wrong with my code i always get the same data repeated in all cells
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.textColor = UIColor.whiteColor()
let query = PFQuery(className:"book")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
var contentString:String = String()
if error == nil {
print("Success retrieved \(objects!.count) scores.")
if let objects = objects {
for object in objects {
let a:String = object.objectForKey("title") as! String
contentString = a
}
}
cell.textLabel!.text = contentString
}}
return cell
}
It will be better to query all your data into viewDidLoad() or any life cycle you would like.
var contentString = [String]() //<-- use an array of string instead of a string variable
override func viewDidLoad()
{
super.viewDidLoad()
let query = PFQuery(className:"book"){ query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
print("Success retrieved \(objects!.count) scores.")
if let objects = objects {
for object in objects
{
let value = object["title"] as! String
self.contentString.append(value) //<-- save the query value to your array
}
self.tableView.reloadData() //<--- then you reload your UI
}
}}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.textColor = UIColor.whiteColor()
cell.textLabel!.text = self.contentString[indexPath.row] //<-- then assign the value into your cell
return cell
}
content inside your loop should be like this.
let a:String = object.objectForKey("title") as! String
contentString += a
and i noticed your block calls for same query always. can you tell me whats the different there
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
var contentString:String = String()
if error == nil {
print("Success retrieved \(objects!.count) scores.")
if let objects = objects {
for object in objects {
let a:String = object.objectForKey("title") as! String
contentString = a
}
}
cell.textLabel!.text = contentString
}}
The query in cellForRowAtIndex is trouble. Imagine, every time a cell comes into view, the code asks for every book from the server.
Put the query outside the datasource method (viewWillAppear, for example). When the query is complete, initialize an array property with the results (e.g. self.bookObjects = objects).
Then in cellForRowAtIndex...
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.textColor = UIColor.whiteColor()
// this is the important idea...
let object = self.bookObjects[indexPath.row]
let a:String = object.objectForKey("title") as! String
cell.textLabel!.text = a
return cell

Unable to load and display data from parse

var findPublisher:PFQuery = PFUser.query()!
findPublisher.whereKey("objectId", equalTo: quote.objectForKey("publisher")!)
findPublisher.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFUser] {
for object in objects {
//println(object.objectId)
let user:PFuser = (objects as NSArray).lastObject as PFUser
cell.publisherLabel.text = user.username
}
}
}
// Configure the cell...
}
The code here is supposed to query for the objectId and display the username instead of the label. I am getting an error that says use of undeclared type of 'PFUser'... I used "println" right after the error == nil statement and it logs correctly so the error definitely occurs after there.
if you are using a TableViewController, you don't need to create an Outlet of the tableview. So you need to query all the objects from the _User class into an array. So it is up to you to know where you want to place this code either in the ViewDidLoad or ViewWillAppear.
var arrayOFUser :NSMutableArray = []
var findPublisher:PFQuery = PFQuery(className:"_User")
findPublisher.findObjectsInBackgroundWithBlock{ (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil{
if let objects = objects as? [PFObject] {
for object in objects {
var getusername = object["username"] as! String
self.arrayOFUser.addObject(getusername)
self.tableview.reloadData()
}
}
}
}
// return the count of user into the each cell in the tableview
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrayOFUser.count
}
then you go into the ** cellForRowAtIndexPath** method
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = self.tableview.dequeueReusableCellWithIdentifier("CellSubtitle", forIndexPath: indexPath) as! UITableViewCell
let name = self.arrayOFUser[indexPath.row] as! String
cell.textlabel?.text = name
return cell
}
QuickNote "CellSubtitle" is the name of the cell in the tableview so go into the storyboard in change it.

Swift: UICollectionView & UIImage fatal error: Array index out of range

Hi Im new to swift and need some help thank you. The program worked once, tried to run it again then it crashed. The items are in the array when I debugged but when I try to display the images I get the fatal error.
// Get Brands
func getBrand () {
// Create PFQuery
var query:PFQuery = PFQuery(className: "BrandInfo")
// Call findobjects
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]?, error: NSError?) -> Void in
// refresh array
self.brands = [String]()
self.pics = [UIImage]()
// loop through array
for brandObject in objects! {
// get PFObjects
let brandName:String? = (brandObject as! PFObject)["Name"] as? String
if brandName != nil {
self.brands.append(brandName!)
}
let brandPicture = brandObject["Image"] as! PFFile
brandPicture.getDataInBackgroundWithBlock({ (imageData:NSData?, error:NSError?) -> Void in
if(error == nil){
let brandImage = UIImage(data: imageData!)
self.pics.append(brandImage)
println(self.pics.count)
}
})
}
// Refresh CollectionView
self.collectionView.reloadData()
}
}
// Setting up collection view
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.brands.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:collectionViewCell = self.collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! collectionViewCell
// Get elements
let picToDisplay:UIImage? = pics[indexPath.row] // this is the error line
let dataToDisplay:String = brands[indexPath.row]
let imageView:UIImageView? = cell.viewWithTag(2) as? UIImageView
// Set labels
cell.brandImage.image = picToDisplay
cell.brandLabel.text = dataToDisplay
return cell
}
///////////////////////////////
struct brandCollection {
var brandText:[String] = [String]()
var brandImage:[UIImage?] = [UIImage]()
}
You have brands.count items, and you need brand.count images. But you are using a different array pics which will fail if it has less elements than brands. Looking at your code, there are several possibilities why this could happen.
This is bad design. You should have a data array that encapsulates all the information you need. Each image should be connected to its object (the brand), not held in some other array.