Access properties of objects in an array- Swift 3.0 - ios

I create a struct in a ViewController file which has the properties url, img, and name. Here is that code:
struct Article {
var url: URL
var img: URL
var title: String
init(url: URL, img: URL, title: String) {
self.url = url
self.img = img
self.title = title
}
}
When the user presses a button, I create an instance of the struct, assign data to the properties, and put it in an array called bookmarks. Then in a TableView file, I want to loop through bookmarks and grab each struct's url, img, and name so I can assign them to labels on each cell.
The trouble I am having is I do not know how to access each struct's properties inside bookmarks.
If anyone could help me accomplish this, that would be amazing. Any help will be appreciated! Thanks so much in advance. Cheers, Theo

You can access the struct's properties with a dot . followed by the property name.
Here is an example:
let article = Article(url: URL(string: ""), img: URL(string: ""), title: "hello")
let theTitle = article.title // equal to "hello"
In your case, you want to grab the information for a table view. Assuming you have an array of Article named bookmarks, simply index into this array in the table view's cellForRowAt indexPath data source method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifierHere")
let article = bookmarks[indexPath.row]
let title = article.title
cell.titleLabel.text = title
return cell
}
This data source method is called on your behalf, so it "loops" through the data array automatically.

Related

How to set a specific value from a struct to a custom cell?

First, I have a struct like this:
struct CodigosAutorizacion {
var codigo: String?
var codigoCancel: String?
var codigoSitio: String?
var codigoCancelsitio: String?
var instancia: String?
init(
code : String? = nil,
codeCancel: String? = nil,
codeSite: String? = nil,
codeSiteCancel: String? = nil,
instance: String? = nil
){
self.codigo = code
self.codigoCancel = codeCancel
self.codigoSitio = codeSite
self.codigoCancelsitio = codeSiteCancel
self.instancia = instance
}
}
This structure values are filled from a web service, then is stored in a array like this:
let codeArray = [
CodigosAutorizacion(
code: validateData!["codigo"] as? String,
codeCancel: validateData!["cancela_codigo"] as? String,
codeSite: validateData!["cod_sitio"] as? String,
codeSiteCancel: validateData!["cancela_cod_sitio"] as? String,
instance: validateData!["instancia"] as? String)
]
codes?.append(codeArray)
now, when I try to give those values to a label inside a table cell(I use a custom cell), I cant access the specific structure value to give to the label.
Example of what I am saying
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let codeCell: DetalleCodigoCell = tableView.dequeueReusableCell(withIdentifier: "CodigoCell", for: indexPath) as! DetalleCodigoCell
codeCell.CodigoNombre.adjustsFontSizeToFitWidth = true
codeCell.codigoNombre.text = codes![indexPath.row].instancia
codeCell.codigoSitio.text = codes![indexPath.row].codigoSitio
codeCell.codigoCancelSitio.text = codes![indexPath.row].codigoCancelsitio
codeCell.codigoInstancia.text = codes![indexPath.row].codigo
codeCell.codigoCancelInstancia.text = codes![indexPath.row].codigoCancel
return codeCell
}
I get the following errors in lines
'codes![indexPath.row].instancia' for example
errors:
-No exact matches in call to subscript
-Reference to member 'instancia' cannot be resolved without a contextual type
I have try accessing directly from 'codeArray' instead of storing it in the intermediate global array 'codes' and accessing but it doesn't work either, as I know this is suppose to be posible but I don't know why I am getting that error.
Any solution?
Thanks in advance.
This is a reference for what I am trying to do:
How to pass specific value to a cell when that cell is selected?
Happy to help. it seems that the issues is about Optionals .
First: adjust your codes to type [CodigosAutorizacion]
Then: in cellForRowAt do some like var x = optional ?? nonOptional
example:
codeCell.codigoNombre.text = codes?[indexPath.row].instancia ?? "0"
reference: https://stackoverflow.com/a/25195633/17771995

How can I include URLs in a Table Struct (Array) and call them in didSelectRowAt?

I am working in xCode 10.2 with swift. I have created global variables in my first view controller for 6 tableviews. In storyboard, I have 6 tableViewControllers. In a separate swift file, I have created a table struct to hold an array and display the data in each corresponding cell. In each view controller in didSelectRowAt connects the next table view. My problem is when I get to the last table view. I need to associate website URLs to the array on the fifth table. I keep getting an error stating cannot convert string to URL. Please Help!
var fifthArray = [
FifthTableStruct(FifthTitle: ["Energy Guide", "https://www.google.com", "Warranty Page", "Use & Care Guide", "Specification Sheet", "FIT System", "Installation Instructions"]),
FifthTableStruct(FifthTitle: ["Energy Guide", "Warranty Page", "Use & Care Guide", "Specification Sheet", "FIT System", "Installation Instructions"])
]
var sixthArray = [
SixthTableStruct(SixthTitle: ["https://www.whirlpool.com/content/dam/global/documents/201708/EnergyGuide-W11037203-RevA.pdf", "https://www.whirlpool.com/content/dam/global/documents/201708/WarrantyPage-W11037201-W.pdf", "https://www.whirlpool.com/content/dam/global/documents/201708/UseandCareGuide-W11037201-RevA.pdf", "https://www.whirlpool.com/content/dam/global/documents/201711/WL170160A_p2.pdf", "https://www.whirlpool.com/content/dam/global/documents/201901/wash-performance-guarantee-en.pdf", "https://www.whirlpool.com/content/dam/global/documents/201711/InstallationInstructions-W10682737-RevA.pdf"])
]
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let urlString = self.sixthArray[indexPath.row]
if let url = URL(fileURLWithPath: urlString)
{
UIApplication.shared.openURL(url)
}
}
I have the code for the tableStruct in an Array file separate from the viewController.
import Foundation
import UIKit
struct SecondTableStruct {
var SecondTitle = [String]()
}
struct ThirdTableStruct {
var ThirdTitle = [String]()
}
struct FourthTableStruct {
var FourthTitle = [String]()
}
struct FifthTableStruct {
var FifthTitle = [String]()
}
struct SixthTableStruct {
var SixthTitle = [String]()
}
sixthArray is an array of SixthTableStructs, a SixthTableStruct has a single field, SixthTitle, whose type is an array of String.
So to get to a single string stored within sixthArray you need to:
Index into sixthArray to obtain a single value of type SixthTable, let's call this intermediate1
Select the SixthTitle field of intermediate1 To obtain a value of type array of String, let's call this intermediate2
Index into intermediate2 to obtain a single String value
In code:
let intermediate1 = sixthArray[someIndex]
let intermediate2 = intermediate1.SixthTitle
let urlString = intermediate2[someOtherIndex]
We can't tell you what the two index values you need are, one is presumably indexPath.row. (You can of course write the above three lines as one without the intermediates if you wish.)
A couple of suggestions, first you appear to have page titles and associated URLs, which form a closely connected pair of data values, broken up and stored in separate arrays requiring you to carefully manage the order of items in those arrays and losing the close association between the items. Consider a single array of some struct, say PageDetails, with appropriate properties, say title and URL, to keep these together.
Second, arrays can hold URLs, not just Strings...
HTH
In your didSelectRowAt do following, Currently you are directly accessing struct but not its array having name SixthTitle
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let urlString = self.sixthArray.SixthTitle[indexPath.row]
if let url = URL(fileURLWithPath: urlString)
{
UIApplication.shared.openURL(url)
}
}

Set image from firebase image URL to a cell in Swift

I am able to get it working if the ImageView is in the same View Controller. But I created a custom cell .xib and a model class. All data (text) seems to be transferring, even the URL of the Firebase database image, but the image doesn't change, the default placeholder image is showing. If I don't set the default placeholder image, I will get an error saying that it is nil.. Again, all cells are populating text data from Firebase, the only thing that isn't is the image from the given URL. Debugging shows that the URL does get passed into the "profileImageURL" variable. Here is some of the code:
class Profile{
var name: String = ""
var age: String = ""
var profileImg : UIImageView! = UIImageView.init(image: "main"))
var description : String = ""
}
Here is the table view controller code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellTableViewCell", for: indexPath) as! CustomCellTableViewCell
let profile = profileArray[indexPath.row]
// Configure the cell...
profileTableView.rowHeight = 300
cell.nameLbl.text = profile.name
cell.descriptionLbl.text = profile.description
cell.profileImage.image = UIImage(named: "main")
return cell
}
func retrievePosts(){
let dataRef = Database.database().reference()
let postsDB = dataRef.child("Messages")
postsDB.observe(.childAdded) { (snapshot) in
let value = snapshot.value as! Dictionary<String,String>
let text = value["postText"]!
let profileImgURL = value["postImage"]!
let userID = value["sender"]!
let url = NSURL(string:"\(profileImgURL)")
let profile = Profile()
profile.description = text
profile.name = name as! String
profile.profileImg.sd_setImage(with: URL(string:profileImgURL), placeholderImage: nil)
self.profileTableView.reloadData()
self.profileArray.insert(profile, at: 0)
})
}
here is the firebase data structure:
- Messages
-L4IkuSxWDnsiJvTKoo0
-postImage: "https://firebasestorage.googleapis.co......"
-postText: "Lorem ipsum dolor sit er elit lamet, consecteta..."
-sender: "C19ghii6OVPNnzJNYPvVJeKuoi73"
bro, the image for any cell is meant to be set in cellForRowAt method. You are getting the raw data because you are fetching it from profile instead of hardcoding, whereas for the image you are setting the image as "main" each time. Hope this helps. – Ashish Sharma
Yup! Thank you! New to App dev. That was it. Had to create a new variable in Profile to hold the url and then in cellForRowAt set the Imageview with that variable URL. There is most likely an easier way to do it but worked for me! Thank you so much! – Guillermo Greco
It's not really the solution, but an alternative:
Use kingfisher pod to set images from URLs.
let url = URL(string: "https://example.com/image.jpg")!
imageView.kf.setImage(with: url)
https://github.com/onevcat/Kingfisher

IOS Swift reading data from a dictionary of [String: [AnotherKindOfDictionary] ] ( )

I would like to read data from a dictionary that contains dictionaries of images (or any sort of object really). Each dictionary has a key (the String).
For a somewhat visual understanding this is what I am trying to achieve:
userIdOne -> [image1, image2, image3, image4]
userIdTwo -> [image1, image2, image3]
userIdThree -> [image1, image2, image3, image4, image5]
userIdFour -> [image1, image2]
NOTE: these images are not the same image despite having the same "title". They just belong to each individual user. The userId is the [String:... and the dictionary of images is the [AnotherKindOfDictionary] I mentioned in the title of this question. I want each userId and their images in each cell. So in total, this would show 4 cells, BUT when tapped, their images would show in sequential order.
The problem is that I want to put this data in a UITableView or UICollectionView. I've worked with both before so whichever works.
Something similar to how snapchat works. Whenever a cell is tapped, the images from that user are shown sequentially.
I've been able to load the data into the dictionary with each userID being the key but I am having trouble using the data in a collectionView(my current choice, although I can use a tableView)
Here is my code:
var stories = [String : [StoryMedia]]()
// StoryMedia is a struct containing info
struct StoryMedia {
var storyMediaId: String?
var creatorId: String?
var datePosted: String?
var imageUrl: String?
init(storyMediaKey: String, dict: Dictionary<String, AnyObject>) {
storyMediaId = storyMediaKey
creatorId = dict["creatorId"] as? String
datePosted = dict["dateposted"] as? String
imageUrl = dict["imageUrl"] as? String
}
}
... Now in the actual viewController class UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stories.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let storyCell: StoryCell!
storyCell = collectionView.dequeueReusableCell(withReuseIdentifier: storyReuseIdentifier, for: indexPath) as! StoryCell
// What should I do here?
return storyCell
}
The problem lies with trying to setup each cell. I cannot pull each dictionary value by its key and use it for each cell.
I've tried using:
// Failed attempt 1)
let story = stories[indexPath.row]
// but I get an ambiguous reference to member 'subscript' error
// Failed attempt 2)
for story in stories {
let creatorId = story.key
let sequenceOfStoryItems = story.value
for singleStoryItem in sequenceOfStoryItems {
// do something...
}
}
// but looping through an array for a collection view cell
// does nothing to display the data and if I were to guess,
// would be detrimental to memory if
// I had a lot of "friends" or users in my "timeline"
A dictionary isn't ordered, so it's awkward to use that for the cellForItem function (and why you can't use that subscript). You might be able to use the dictionary's values (i.e. ignore the keys), but that could be different b/n runs. What I mean is, you can use the subscript on the stories.values array (don't remember the exact call for "values", but it's close...allValues?...not sure, don't have a way to double check right now) instead of the stories dictionary.
Does var stories = [String : [StoryMedia]]() need to be a Dictionary?
Dictionaries aren't ordered, so can't index them like you are asking. Can you make it an array of tuples? var stories = [(username:String, media:StoryMedia)]() Then you can add whatever value you were planning to store in the original key into the username: field on the tuple. You could make another struct that has username and media properties if you prefer over the tuple.
It should be trivial to pull individual username or media structs out of the array with a simple stories.filter{} call.

View Parse PFFile PDF in WebView using Xcode7 and Swift 2

I have an iOS project I'm working on using Xcode7 and Swift2. I have a PDF that is saving to Parse. It is saving to a Parse Class called IncomingRecipe. In this Class is a FileName column with type as a String. It also has a column called PDFData and is type PFFile. I want it so when the user clicks on a TableViewCell it segues to a new View Controller and displays the PDF in a WebView.
Currently these fileNames are in a TableView. I have a segue that goes to the View Controller with the WebView. It passes along the name of the fileName from the TableViewCell as a Global variable.
My query for the data for the TableView code for parse is:
var fileName = [String]()
var PDFData = [PFFile]()
var getRecipeQuery = PFQuery(className: "IncomingRecipe")
// Match the query with only items that the current user uploaded
getRecipeQuery.whereKey("userId", equalTo: appUserId)
getRecipeQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
// Check to see if 'objects' exist
if let objects = objects {
for object in objects {
// An AnyObject that needs to be cast as a String
var recipeName = object["fileName"] as! String
self.fileName.append(object["fileName"] as! String)
self.objectid.append(object["objectid"] as! String)
self.userId.append(object["userId"] as! String)
self.PDFData.append(object["PDFData"] as! PFFile)
self.myFilesTable.reloadData()
}
}
}
The TableView loads the fileName as:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "PDFTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! PDFTableViewCell
cell.textLabel?.text = fileName[indexPath.row]
return cell
}
I have the code for passing the selected cell fileName to a Global variable as:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ItemView" {
let savedRecipedView = segue.destinationViewController as! PDFItemViewController
if let selectedRecipeCell = sender as? PDFTableViewCell {
let indexPath = myFilesTable.indexPathForCell(selectedRecipeCell)!
viewingPDFRecipe = fileName[indexPath.row]
print("Sending Click: \(viewingPDFRecipe)")
}
}
}
How can I get the PFFile of the PDA and display it in the WebView on the other View Controller? I can't figure out how to get all of this into a URL to be used with the WebView. I looked here and tried to implement this with mine, with no success. Thank you.
Don't just save the file name with
self.fileName.append(object["fileName"] as! String)
save the whole list of PFObjects. These objects will contain the file name (that you can use for the table view) and the PFFile reference (that you can use on drill down). Also, you don't appear to, but you shouldn't pass by global. It just looks like you're passing the file name in the segue.
Instead of passing the file name you should pass the whole PFObject. Then, in the destination view controller you can extract the PFFile reference and the URL it contains.

Resources