Swift append array value not showing outside statement - arrays

My scenario from my get call I received values and I appended with var nameData = [String]() array. nameData array values not showing outside statement. Please check my below code
// Global Declarions
var nameData = [String]()
// GET Call values append
if let content = result["contacts"] as? [[String:AnyObject]] {
for category in content {
self.nameData.append(category["name"] as! String)
}
print(self.nameData) // here I am getting
}
}
self.addDropDown()
print(self.nameData) // Empty array showing
Now, My dropdown code below, Here I want to assign nameData array
func addDropDown(){
print(self.nameData) // Empty array showing why???
// For Top textField
let dropDownTop = VPAutoComplete()
dropDownTop.dataSource = self.nameData -->// Here I need to assign nameData values if i do its showing empty values.
dropDownTop.onTextField = emailTF
dropDownTop.onView = self.view
dropDownTop.show { (str, index) in
print("string : \(str) and Index : \(index)")
self.emailTF.text = str
}
}

Try this:
if let content = result["contacts"] as? [[String:AnyObject]] {
for category in content {
self.nameData.append(category["name"] as! String)
}
DispatchQueue.main.async { self.addDropDown() }
}
}
Add the drop down just after you fill the nameData array.

Related

Assigning String to Array is Returning Nil - Swift

When web scraping my forum in swift I can run the following code to print in console the titles of each forum topic:
enum HTMLError: Error {
case badInnerHTML
}
class DiscussionBoardResponse {
init(_ innerHTML: Any?) throws {
guard let htmlString = innerHTML as? String else { throw HTMLError.badInnerHTML }
let doc = try SwiftSoup.parse(htmlString)
let titles = try doc.getElementsByClass("Forum_NormalBold").array()
var nestedLoginController: LoginController!
for i in 0..<titles.count {
let title = try titles[i].text()
print(title)
print("")
}
}
}
Now above I need to assign what is in the title to an array outside of the class. So I created a variable (which could be wrong and maybe that is the issue):
var discussionTitles = [String?]()
My viewController is named LoginController. Now I tried adding this to the DiscussionBoardResponse to assign titles to the variable:
class DiscussionBoardResponse {
//let discussionTopics: [DiscussionTopicSingle]
init(_ innerHTML: Any?) throws {
guard let htmlString = innerHTML as? String else { throw HTMLError.badInnerHTML }
let doc = try SwiftSoup.parse(htmlString)
let titles = try doc.getElementsByClass("Forum_NormalBold").array()
var nestedLoginController: LoginController!
for i in 0..<titles.count {
let title = try titles[i].text()
//tried converting title into a string in case it was't
//guard let titleString = title as? String else { return }
nestedLoginController?.discussionTitles[i] = title
print(nestedLoginController?.discussionTitles[i])
print("")
}
}
}
Now when I print the nestedLoginController?.discussionTitles[I] It only prints out nil for every title. What am I doing wrong?
UPDATE: Im now rethinking a little on how to do this because the other way is not working, so inside where I click the button which takes me to DiscussionBoardResponse looks like this:
do {
let discussionResponse = try DiscussionBoardResponse(innerLoginHTML)
print("Got Response")
} catch{}
I attempt to send over the variable discussionTitles
let discussionResponse = try DiscussionBoardResponse(innerLoginHTML, test: self.discussionTitles)
and in the DiscussionResponse I have now:
init(_ innerHTML: Any?, test: [String] = []) throws {
guard let htmlString = innerHTML as? String else { throw HTMLError.badInnerHTML }
let doc = try SwiftSoup.parse(htmlString)
let titles = try doc.getElementsByClass("Forum_NormalBold").array()
//var nestedLoginDelete: [String] = []
for i in 0..<titles.count {
let title = try titles[i].text()
test.append(title)
}
}
}
and I now get the error: Cannot use mutating member on immutable value: 'test' is a 'let' constant. Im not sure even if this worked is im actually manipulating the variable discussionTitles or if im just manipulating some instance of it? Either way what am I doing wrong?

Issue with storing data within an Array - Swift

I currently have my set-up as followed:
I am running a query in Firebase to extract all of the genres within an array of genres, like so:
var genresLabelIndex : [String] = ["Horror", "Fiction", "Romance"]
Then I am creating a blank arrays for each of the genres to be able to store the information of the genres within each of the areas like so:
var horrorData = [InformationForFeed]()
var fictionData = [InformationForFeed]()
var romanceData = [InformationForFeed]()
InformationForFeed looks like so:
class InformationForFeed {
fileprivate var _uploadKey:String!
fileprivate var _userKey:String!
fileprivate var _imageURL:String!
fileprivate var _socialMedia:[String]
var uploadKey:String!{
return _uploadKey
}
var userKey:String!{
return _userKey
}
var imageURL:String!{
return _imageURL
}
init(dictionary:Dictionary<String,AnyObject>, socials: [String]) {
_socialMedia = socials
if let uploadKey = dictionary["upload_key"] as? String {
self._uploadKey = uploadKey
}
if let userKey = dictionary["user_key"] as? String {
self._userKey = userKey
}
if let imageURL = dictionary["imageUrl"] as? String {
self._imageURL = imageURL
}
}
}
I am then creating an Array of the list of genres arrays like so:
1) First I am creating an empty array of arrays like this:
var genreArrayIndex : [[InformationForFeed]] = []
2) Then within my init() of the UIView I am setting what will be in the array like this:
genreArrayIndex = [self.horrorData, self.fictionData, self.romanceData]
I then will run a function called getData() that will run my query and start storing the information.
I store my information of each genre in a tempArray, and then I set the genreArrayIndex[index] to equal the tempArray and then clear the tempArray as seen in getData below.
func getData() {
for genre in genresLabelIndex {
let dbReference = Database.database().reference().child("genres").child(genre)
let query = dbReference.queryLimited(toLast: 6)
query.observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
if snapshot.childrenCount > 0 {
for s in snapshot.children.allObjects as! [DataSnapshot] {
let item = s.value as! Dictionary<String,AnyObject?>
let facebook = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["facebook_link"]
let audible = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["audible_link"]
let amazon = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["amazon_link"]
var socialsArray = [String]()
if facebook != nil {
socialsArray.append(facebook! as! String)
} else {
socialsArray.append("nil")
}
if audible != nil {
socialsArray.append(audible! as! String)
} else {
socialsArray.append("nil")
}
if amazon != nil {
socialsArray.append(amazon! as! String)
} else {
socialsArray.append("nil")
}
let data = InformationForFeed(dictionary: item as Dictionary<String,AnyObject>, socials: socialsArray)
self.newArray.append(data)
}
}
self.genreArrayIndex[self.genreArrayIndexCount] = self.newArray
self.genreArrayIndexCount = self.genreArrayIndexCount + 1
self.newArray.removeAll()
self.internalIndex = self.internalIndex + 1
if self.internalIndex == self.genresLabelIndex.count {
self.tableView.reloadData()
}
})
}
}
My tempArray looks like this:
var newArray = [InformationForFeed]()
The index looks like this:
var genreArrayIndexCount : Int = 0
Now comes the issue....
All of the information is properly being stored in the genreArrayIndex .....but... it is not actually storing the information in the arrays that being stored in genreArrayIndex.
So in other words if you were to print(self.genreArrayIndex) it would be fully populated. But if you were to print(self.fictionData) it would be blank.
How can I resolve this?
Array is a value type. That means its contents are copies. Initializing genreArrayIndex with empty horrorData, (and others) and then filling it with getData() does not also copy the data back into horrorData. I would recommend eliminating
genreArrayIndex = [self.horrorData, self.fictionData, self.romanceData]
and replacing horrorData, fictionData, ... with computed properties. Perhaps like this.
var horrorData: [InformationFeed] {
return genreArrayIndex[0]
}

Add Parse array to dictionary swift

I have some objects in parse and I am getting the data successfully as [PFObjects]. The issue is that I am trying to add the array elements [PFObjects] to a dictionary as values. But I keep getting an empty dictionary, so the values are not added to the dictionary. The dictionary count is also 0.
This is what I tried so far:
var postDictionary = [String:[AnyObject]]()
query.findObjectsInBackground(block: { (posts: [PFObject]?, error:Error?) in
if let unwrappedPosts = posts {
for posts in unwrappedPosts {
if let postText = posts.object(forKey: "title") as?String {
self.titleArray.append(postText)
print("count", self.titleArray.count) // count 10
self.postDictionary["title"]?.append(self.titleArray as AnyObject)
**try to force unwrap **
self.postDictionary["title"]!.append(self.titleArray as AnyObject), and the app crashed
for (title, text) in self.postDictionary {
print("\(title) = \(text)")
}
print("Dictionay text count",self.postDictionary.count) // count is 0
}
}
}
})
This syntax is very confusing
self.titleArray.append(postText)
self.postDictionary["title"]?.append(self.titleArray as AnyObject)
You append a string to an array and then you are going to append the array to the array in the dictionary. I guess this is not intended.
I recommend to map the title strings and set the array for key title once
var postDictionary = [String:[String]]()
query.findObjectsInBackground(block: { (posts: [PFObject]?, error:Error?) in
if let unwrappedPosts = posts {
self.titleArray = unwrappedPosts.compactMap { $0.object(forKey: "title") as? String }
self.postDictionary["title"] = self.titleArray
for (title, text) in self.postDictionary {
print("\(title) = \(text)")
}
print("Dictionay text count",self.postDictionary.count) // count is 0
}
})
Never use AnyObject if the type is more specific.
The proper way of adding to a dictionary is using updateValue because as far as i can see that you don't have the key "title" in your dictionary and you are appending values to unknown key i guess.
This should help:
titleArray.append(postText)
postDictionary.updateValue(titleArray as [AnyObject], forKey: "title")
for (key,value) in postDictionary {
print("\(key) \(value)")
}
Finally this should print:
title [posts1, posts2, posts3]

Filtering arrays for use with UISearchBar

I have a table view which displays a user's Name, Company Name and Photo (PFFile). Each tableView row I have has all of this information in it.
I am using UISearchBarDelegate and IB to implement a search function to filter by the user's Name. It is finding the correct user but I have not been able to also update the company photo.
How do I filter the other arrays? The items I need from the arrays will be at the same index as the ones taken from the user's Name array.
EDIT: I am trying a different data structure and am receiving array index out of range, updated code below:
var filterArray = [User]() //<-- globally declared
var userArray = [User]() //< Global
class User {
var name: String?
var company: String?
init (name: String?, company: String?) {
self.name = name
self.company = company
}
}
//In a class which populates the search arrays
for object in unwrappedSucceeded {
let username = object.valueForKey("username") as! String
let companyName = object.valueForKey("companyName") as! String
let user = User(name: username, company: companyName)
userArray.append(user)
}
//tableViewController
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
filterArray.removeAll(keepCapacity: false)
if searchText.characters.count != 0 {
isSearch = true
self.search(searchText)
} else {
isSearch = false
}
}
func search(text: String) -> Void {
filterArray = userArray.filter({$0.name == text})
}
//In cellForRowAtIndexPath
cell.usernameCell.text = filterArray[indexPath.row].name //ARRAY INDEX OUT OF RANGE
Like I said you strongly recommend to group each user's info into one big container, therefore we could use array of struct or class, then it comes easier to filter.
schematic for the container:
struct Container
{
var username:String?
var companyName:String?
var photo:UIImage?
}
your main array will be : var arrayofData = [Container]()
Now when you are query your objects from parse, inside of your query function
// after you called the findObjectsWithBackgroundBlock()
// let's assume you check for error and if the [PFObject] is empty or not
for one in objectsFromParse
{
let photoToget = one["Photo"] as! PFFile
// next step should be to get the image data right :)
{
// let's assume that is the block when get the image data right:)
// check your data and assign it to some UIImage
// then
let userRepresentation = Container() //<-- we are creating a single object representation for each user
let username = one["username"] as! String //<--data we got from Parse
let companyName = one["companyName"] as! String
let userImage = //the UIImage which contains the data
userRepresentation.username = username
userRepresentation.companyName = companyName
userRepresentation.photo = userImage
// then we append
arrayOfData.append(userRepresentation)
}
}
Now we have all data into our array, so let's filter by username and also I hope you configure your tableView so when you have data from filter or regular array.
var filterArray = [Container]() //<-- globally declared
func search(text: String) -> Void
{
filterArray = arrayOfData.filter(){ (Container) -> Bool in
let range = Container.name!.rangeOfString(text, options:NSStringCompareOptions.CaseInsensitiveSearch) return range != nil }
// then you are good to go
}
let arr1 = [10,20,40]
let e1 = arr1.enumerate()
let arr2 = ["a","b","c"]
let f1 = e1.filter { $0.element % 20 == 0 }
let f2 = arr2.enumerate().filter { j, _ in
f1.contains { i, _ in
i == j
}
}
print(f1.map{$0.element}, f2.map{$0.element})
// [20, 40] ["b", "c"]
now you have both arrays "filtered". the best, what you can do is redesigning your data model!

Setting a cells textLabel from an array of [String]()

Trying to access and set my cells textLabel and detail text label to objects i have appended to the array. Im not to sure how to use the right syntax in this case. thanks for the help!
heres the objects I've appended from parse in my for loop.
var customers = [String]()
for object in objects {
self.customers.append(object["customerName"] as! String)
self.customers.append(object["customerStreetAddress"] as! String)
cellForRowAtIndexPath {
cell.textLabel.text = //I want the objects["customerName"] here
cell.detailTextLabel.text = // objects["customerStreetAddress"] here
}
You could try this.
var customers = [String]()
var number = -1
for object in objects {
self.customers.append(object["customerName"] as! String)
self.customers.append(object["customerStreetAddress"] as! String)
cellForRowAtIndexPath {
++number
if number + 1 <= customers.count {
cell.textLabel.text = customers[number]//I want the objects["customerName"] here
}
++number
if number + 1 <= customers.count {
cell.detailTextLabel.text = customers[number]// objects["customerStreetAddress"] here
}
}
}

Resources