Is it possible to make array empty without activating its DidSet property? - arrays

Currently I have an array that activates another function when set:
var updatedBeaconDetailsArray = [BeaconDataDetails]() { didSet {
self.updateBeaconData(beacon: self.updatedBeaconDetailsArray)
}
}
I'm trying to clear the array with activating the didSet since the didSet function is also tied to other parts of the app causing odd behavior.
So far I've tried:
self.updatedBeaconDetailsArray = []
self.updatedBeaconDetailsArray.removeAll()
but they all still activate the didSet, any thoughts?

What if you checked to see if the array is empty inside of the didSet?
Something like:
var updatedBeaconDetailsArray = [BeaconDataDetails]() {
didSet {
if !updatedBeaconDetailsArray.isEmpty {
self.updateBeaconData(beacon: self.updatedBeaconDetailsArray)
}
}
}

Related

how to change value in struct globally in swift

So I have an api request that requests a bunch of data from a fake api url, the data I am getting is being put on a placeholder, I just want to have a global variable to be able to use that array of codable data in my collectionviews.
struct productsList{
static var itemsList = [ProductItem]()
}
func getProducts() {
storeRepo
.getAllProducts()
.subscribe { result in
productsList.itemsList = result
for item in productsList.itemsList{
print(item.category)
}
} onError: { error in
print(error.localizedDescription)
}.disposed(by: disposeBag)
}
func printReuslt() {
for i in productsList.itemsList{
print(i.id)
}
}
note that it's not printing the printResult() but it's looping inside of the .subscribe
note that i am using Moya as well as RXswift
What you're looking for is called a Singleton. Swift makes this extremely easy to do. Basically, the short and sweet is that the struct you create, initializes itself as a property of itself. Anytime you access (In this example) APIHandler.shared you'll get a reference to the only single object, which has your other properties dataObj1 and someObj2 from this example.
class APIHandler {
let shared = APIHandler()
var dataObj1: YourObj?
var someObj2: YourObj2?
init() {
self.someObj1 = yourMethodCall()
self.someObj2 = someCalculation()
}
}
This is how you access it from another class. BE CAREFUL you can access APIHandler.someObj which would result in a null reference exception if you don't have an object created, so when doing this always access the shared property.
class MainClass {
let apiHandler: APIHandler?
override func viewDidLoad(...) {
super.viewDidLoad(...)
apiHandler = APIHandler.shared
}
}

Why Can't I Append to a State Array Within View in SwiftUI?

I'm not sure why this code doesn't work. It builds and runs fine, but nothing is displayed in the view. While debugging, I can see that the append() calls don't actually add the items to the array, but there's no error:
import SwiftUI
struct Test: View {
#State private var array: [String] = []
var body: some View {
self.array.append("A")
self.array.append("B")
self.array.append("C")
return VStack {
ForEach(self.array, id: \.self) {string in
Text(string)
}
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: some View {
Test()
}
}
I've also tried doing the appends in an init(_:) with the same result. It works if I initialize the array with the values like #State private var array: [String] = ["A", "B", "C"] so it seems like there's some immutability of state variables nuance that I'm missing. I'm pretty new to Swift. Can someone please explain what I'm doing wrong here?
I tried to run your code on Xcode 11.4.1, I got a warning saying;
Modifying state during view update, this will cause undefined behavior
This error occurs because you’re trying to modify the state of a SwiftUI view while it is actually being rendered.
So as an alternative you can try appending items in onAppear block
struct Test: View {
State private var array: [String] = []
var body: some View {
VStack {
ForEach(self.array, id: \.self) {string in
Text(string)
}
}.onAppear { // Prefer, Life cycle method
self.array.append("A")
self.array.append("B")
self.array.append("C")
}
}
}
Then you'll be able to see your items in the screen.
Also here is a bit detailed explanation

Updating array value using find object in the background is swift

I'm trying to retrieve data from Parse using findObjectsInbackground and store it in an array. I've already created outside the scoop of viewDidLoad().
I managed retrieving and printing the data, but they are not stored in the array and it keeps being empty!
I used self.articalsTableView.reloadData() but unfortunately the array myArray is still empty.
Any help please, this has been confusing me for two days!
import UIKit
import Parse
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var articalsTableView: UITableView!
var myArray = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Gateshead")
query.findObjectsInBackground {(objects, error) -> Void in
if error != nil {
print(error)
} else {
if let articals = objects {
for artical in articals {
// print (articles) THIS IS WOKING WELL
self.myArray.append(artical)
self.articalsTableView.reloadData()
}
}
}
}
}
}
findObjectsInback is using a background thread and you should dispatch to mainThread whenever if you want to access UIKit stuff in this case updating self.articalsTableView.
Also self.articalsTableView.reloadData() should be called at the end (not in the loop). This to prevent a race condition on self.myArray being accessed by the main-thread (to update self.articalsTableView ) and by the background-thread (to append artical)
for artical in articals {
// print (articles) THIS IS WOKING WELL
self.myArray.append(artical)
}
DispatchQueue.main.async {
self.articalsTableView.reloadData()
}

Swift: trouble with Arrays of classes

I'm trying to create an array of two items: a URL and a String. The index of the items is of significance.
The data is taken from QuartzFilterManager, which provides information about the Quartz Filters installed on a system.
import Cocoa
import Quartz
class myFilter {
var myURL: URL?
var name: String = ""
}
func getFilters() -> Array<String> {
var filterArray: Array<myFilter>
if let Filters = QuartzFilterManager.filters(inDomains: nil) {
for (index, eachFilter) in Filters.enumerated() {
filterArray[index].name.append((eachFilter as! QuartzFilter).localizedName()!)
filterArray[index].myURL!.append((eachFilter as! QuartzFilter).url()!)
}
}
}
Xcode complains about Type URL not having an append method. But the name property in the preceding line works. In short, how do I set specific properties in my array?
There are lots of issues.
Make myFilter a struct instead of class and name it properly as MyFilter.
You never initialize your filterArray, you only declare it.
You need to create a new instance of MyFilter for each url/name pair you want to add to the array.
You don't need to use enumerated in this case.
You have the wrong return type for your getFilter function (I think).
Use proper naming conventions.
Here's cleaned up code:
struct MyFilter {
var myURL: URL?
var name: String
}
func getFilters() -> [MyFilter] {
var filterArray = [MyFilter]()
if let filters = QuartzFilterManager.filters(inDomains: nil) {
for eachFilter in filters {
let filter = MyFilter(myURL: (eachFilter as! QuartzFilter).url(), name: (eachFilter as! QuartzFilter).localizedName()!)
filterArray.append(filter)
}
}
return filterArray
}
It's still not ideal. Having to cast eachFilter using as! QuartzFilter is clunky.
And other uses of ! are bad. Force-unwrapping the call to localizedName() can crash. Consider proper solutions.
Append is a method of the array struct, not of the URL/String.
You first need to create the array (you just declared it, you actually need to assign something to it)
You then need to create the object that you want to append into the array
You can now append this newly created object to the array
It should look something like this:
import Cocoa
import Quartz
class MyFilter {
var myURL: URL?
var name: String?
init(url: URL?, name: String?) {
self.myURL = url
self.name = name
}
}
func getFilters() -> Array<MyFilter> {
var filterArray = [MyFilter]()
if let filters = QuartzFilterManager.filters(inDomains: nil) {
for filter in filters {
let aFilter = MyFilter(url: filter.url(), name: filter.localizedName())
filterArray.append(aFilter)
}
}
return filterArray
}
Now the array returned by this method will have N MyFilter objects.
You can access every object in the array the way you did before, with
let aFilter = filterArray[index]
And to get the property inside of that object:
let url = aFilter.myURL
let name = aFilter.name
PS: I changed some names to fit the swift conventions (classes are written in PascalCase and variables in camelCase)
PpS: be careful with ! in swift, if it's used on something that happens to be nil will crash the app. Read more about optionals here
PpPs: I was just a few minutes late :D

Getting elements from array based on property values (AngularJS)

I have an array of players, each player is an object that has a number of properties, one is "goals".
var players = [
{
"id":"4634",
"name":"A. Turan",
"number":"0",
"age":"28",
"position":"M",
"goals":"1"
},
{
"id":"155410",
"name":"H. Çalhano?lu",
"number":"0",
"age":"21",
"position":"A",
"goals":"0"
},
{
"id":"4788",
"name":"B. Y?lmaz",
"number":"0",
"age":"30",
"position":"A",
"goals":"2",
}
]
I've written a function to cycle through the array and push every element that has more than '0' goals to an array, topScorers. Like so:
$scope.topScorerSearch = function() {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.goals > 0) {
topScorers.push(o)
}
});
return topScorers;
}
With the function called as {{topScorerSearch()}}.
This returns only players who have scored. Perfect.
However, I want to run this on other properties, which will result in a lot of repetitious code. How can I make this a general purpose function that can be executed on different properties?
I tried including the 'prop' parameter, but it didn't work:
$scope.topScorerSearch = function(prop) {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.prop > 0) {
topScorers.push(o)
}
});
return topScorers;
}
...and called the function like this:
{{topScorerSearch(goals)}}
Why doesn't this work? Where am I going wrong?
I believe the issue is that prop will not resolve to goals because goals is being treated as a variable with a null or undefined value, making prop null or undefined.
If you use the alternative way of accessing object properties object["property"] and use the function {{topScorers("goals")}} it should work out.

Resources