Array not being seen in scope Im not sure why SwiftUI - arrays

Code:
extension Array {
// Total Together An Array
func FindTotal(_ arrayName: [Int]) -> Int {
var currentValue: Int = 0
for i in 0...Int(arrayName.count - 1) {
currentValue = currentValue + Int(arrayName[i])
}
return currentValue
}
// Number Grabber for Calculating the values
func calcItemsD(_ TargetArray: [String]) {
var placeholder: String? = nil
for i in 0...Int(TargetArray.count - 1) {
placeholder = String((TargetArray[i]).character(at: 0)!)
if (placeholder == "1") {
dealerNums.append("")
}
}
}
}
class DeckSetup : ObservableObject {
#Published public var deckOCards: [String] = []
#Published public var yourhand: [String] = []
#Published public var dealerHand: [String] = []
#Published public var dealerNums: [Int] = [7, 2]
#Published public var playerNums: [Int] = []
}
The dealerNums.append("") is throwing the error of out of scope and I am not sure why Heres the all the code that should be relevant.

dealerNums is an array encapsulated in your DeckSetup class. You can't access that from an Array extension.
What you can do, is pass in dealerNums into the function, like so:
func calcItemsD(_ targetArray: [String], dealerNums: inout [Int]) {
var placeholder: String? = nil
for i in 0 ..< targetArray.count {
placeholder = String(targetArray[i].first!)
if placeholder == "1" {
dealerNums.append("")
}
}
}
And called like so from inside your DeckSetup class:
calcItemsD(["1", "K", "A"], dealerNums: &dealerNums)
dealerNums is marked inout, since you are mutating it within the function.
I cleaned up the function a tiny bit, but I don't know if you have more to it. For example, these are more things you could change to improve it:
Iterate with for target in targetArray instead of using the index.
placeholder is not needed to be stored outside the loop as it isn't used. You can have a local let placeholder = ... if needed.
Don't force unwrap (!) the first character. Provide a suitable alternative or fallback.

Related

How to create subarrays without duplication Swift

I have a Meal structure in my SwiftUI project
struct Meal: Identifiable, Codable, Equatable {
var id = UUID().uuidString
var name: String
var time: String
var type: String
var recommendation: Bool
}
I also have the ContentViewModel class
class ContentViewModel: ObservableObject {
init() {
let allItemsInit = Bundle.main.decode([Meal].self, from: "menu.json")
self.allItems = allItemsInit
self.recomendationItems = allItemsInit.filter {$0.recommendation == true}
}
#Published var allItems: [Meal] = []
#Published var recomendationItems: [Meal] = []
}
Is it a correct approach that I just assign certain elements to the new array of recomendationItems, thereby duplicating them.
recomendationItems - just example, there will be a large number of such subarrays.
You don't need "subarrays" -- your View will get updated whenever allItems changes, so you can use other computed properties to provide the subarrays rather than making them actual separate containers.
For example:
class ContentViewModel: ObservableObject {
init() {
self.allItems = Bundle.main.decode([Meal].self, from: "menu.json")
}
#Published var allItems: [Meal] = []
var recommendedItems: [Meal] {
return allItems.filter {$0.recommendation == true}
}
}

How eliminate duplicate objects from array of objects in swift

I am having two arrays coming from web service, I need to find out whether the Array2 has the same objects as Array1.
So, For this I am using below code:
var arr1 = [CustomObject]()
var arr2 = [CustomObject]()
var arr3 = [CustomObject]()
var arr4 = [CustomObject]()
self.arr3 = self.arr1 + self.arr2 //concatenate two arrays
self.arr4 = Array(Set(arr3)) // find out uniq values
// below is the extension
extension Array where Element : Hashable {
var unique: [Element] {
var uniqueValues: [Element] = []
forEach { item in
if !uniqueValues.contains(item) {
uniqueValues += [item]
}
}
return uniqueValues
}
}
But it is showing error on above line "Array(Set(arr3))"
Error Is :- To add value to Set
Try this :
var arr1 = ["A","B","C"]
var arr2 = ["A","B","C"]
if Set(arr1).symmetricDifference(arr2).isEmpty {
print("The Arrays Match")
}
Overview:
In order for the set to store custom class / struct, the custom class / struct needs to to conform to Hashable protocol and indirectly Equatable protocol.
Given below is an example using a struct, you can use a class as well.
Code:
struct CustomObject : Hashable{
var something : Int //It is just an example, this could be any type, but some how you should find a way to compute the hash value.
//MARK: Hashable
var hashValue: Int {
return something
}
}
//MARK: CustomObject - Equatable
func ==(lhs: CustomObject, rhs: CustomObject) -> Bool {
return lhs.something == rhs.something
}

Swift: How to define a fixed array of flexible String array

I already have several arrays for strings. I want to add them to a list of arrays, so I can use a predefined (enum) index. The individual arrays are already in place, I only need to access them via index (fixed with enum or within a loop with index from enum type). So there should be no copy of the strings within the array, only a reference to the array itself.
I already have this in mind:
enum TypeOfArray: Int {
case Src = 0, Dest, SrcCache, DstCache, N
}
var srcFolders : [String] = []
var dstFolders : [String] = []
var srcFoldersCache : [String] = []
var dstFoldersCache : [String] = []
var allFolders: [[String]] = []
Then I want to initilaze the main array by assigning each of the individual arrays. But this is rejected by the compiler: ("Cannot subscript a value of type '[[String]]' with an index of type 'TypeArray'")
allFolders[TypeOfArray.Src] = srcFolders
I don't know if this "typesave" index is even possible.
Can I use a fixed index range 0..N when defining for optimizing memory or speed?
Any ideas?
A dictionary would be a good solution for this:
var dict = [TypeOfArray:[String]]()
dict[TypeOfArray.Src] = srcFolders
Singleton
If you want to share the content of your arrays, an you want the updates to be reflected in your code, you can use a Singleton
final class ImageNameManager {
static let sharedInstance = ImageNameManager()
var srcFolders: [String]
var dstFolders: [String]
var srcFoldersCache: [String]
var dstFoldersCache: [String]
private init() {
// populate: srcFolders, dstFolders, srcFoldersCache, dstFoldersCache
srcFolders = []
dstFolders = []
srcFoldersCache = []
dstFoldersCache = []
}
enum ImageType: Int {
case Src = 0, Dest, SrcCache, DstCache
}
func imageNames(imageType: ImageType) -> [String] {
switch imageType {
case .Src: return srcFolders
case .Dest: return dstFolders
case .SrcCache: return srcFoldersCache
case .DstCache: return dstFoldersCache
}
}
}
Usage
Now you can populate one of your array
ImageNameManager.sharedInstance.dstFolders.append("Hello")
and receives the new data in another section of your code
let dstFolders = ImageNameManager.sharedInstance.imageNames(.Dest)
// ["Hello"]
Update
In order to share the same array across your app you cal also use this code
final class ImageNameManager {
static let sharedInstance = ImageNameManager()
var srcFolders: [String] = []
var dstFolders: [String] = []
var srcFoldersCache: [String] = []
var dstFoldersCache: [String] = []
}
Now alway reference it the array with this code ImageNameManager.sharedInstance.dstFolders, look
ImageNameManager.sharedInstance.dstFolders.append("Hello")
ImageNameManager.sharedInstance.dstFolders.append("World")
ImageNameManager.sharedInstance.dstFolders // ["Hello", "World"]

How to encode an array of CGPoints with NSCoder in Swift?

I am trying to save a copy of my custom class to a file, my class has 2 arrays of CGPoints which I append to every so often, they look like this:
class BlockAttributes: NSObject {
var positions:[CGPoint] = []
var spawns:[CGPoint] = []
}
Everything is working great as far as just as using and accessing the class goes, but archiving it does not work. I can archive arrays of Strings, Bools, and Ints just fine in my other classes but my game fails every time I try to use NSCoder to encode my arrays of CGPoints. Here is my code for archiving:
func encodeWithCoder(coder: NSCoder!) {
coder.encodeObject(positions, forKey: "positions")
coder.encodeObject(spawns, forKey: "spawns")
}
....
class ArchiveData: NSObject {
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func saveData(data: BlockAttributes) {
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as! String
path = documentDirectory.stringByAppendingPathComponent("data.archive")
if NSKeyedArchiver.archiveRootObject(data, toFile: path) {
print("Success writing to file!")
} else {
print("Unable to write to file!")
}
}
func retrieveData() -> NSObject {
var dataToRetrieve = BlockAttributes()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as! String
path = documentDirectory.stringByAppendingPathComponent("data.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? BlockAttributes {
dataToRetrieve = dataToRetrieve2 as BlockAttributes
}
return(dataToRetrieve)
}
}
....
And to save:
let archiveData = ArchiveData()
archiveData.saveData(myBlockActionsObject)
I even tried creating my own custom class to save the CGPoints to, which I call MyCGPoint (I read somewhere on SO that creating custom classes for some data types resolves some NSCoder issues):
class MyCGPoint: NSObject {
var x: CGFloat = 0.0
var y: CGFloat = 0.0
init(X: CGFloat, Y: CGFloat) {
x = X
y = Y
}
override init() {
}
}
....
class BlockAttributes: NSObject {
var positions:[MyCGPoint] = []
var spawns:[MyCGPoint] = []
}
But alas, I am still getting this error:
[Game.MyCGPoint encodeWithCoder:]:
unrecognized selector sent to instance 0x137f1d1a0 Game[20953:5814436]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[Game.MyCGPoint encodeWithCoder:]:
unrecognized selector sent to instance 0x137f1d1a0'
Any idea how I can use encodeObject to encode my array of CGPoints/MyCGPoints?
You can convert them to and from strings:
//To string
let point = CGPointMake(0, 0)
let string = NSStringFromCGPoint(point)
//Or if you want String instead of NSString
let string = String(point)
//From string
let point2 = CGPointFromString(string)
CGPoint (and its Cocoa's twin NSPoint) are structs, i.e. value type, so you can't encode them directly. Wrap them in NSValue:
let positionValues = positions.map { NSValue(point:$0) }
let spawnValues = spawns.map { NSValue(point:$0) }
coder.encodeObject(positionValues, forKey: "positions")
coder.encodeObject(spawnValues, forKey: "spawns")
// Decode:
positons = (coder.decodeObjectForKey("positions") as! [NSValue]).map { $0.pointValue }
spawns = (coder.decodeObjectForKey("spawns") as! [NSValue]).map { $0.pointValue }
When you write your custom wrapper class, you have to make it compliant with NSCoding too, which NSValeu had already done for you, for free.

Change array back to dictionary - SWIFT

I have a for loop that creates a dictionary and then I append the dictionary to an array. I append the dictionary to an array because I don't know how to add more than one value with the same key, when I do that in the for loop the key / value pair is just updated and the old key / value pair is deleted What is the best way to change the array back to a dictionary?
import UIKit
class ViewController: UIViewController {
var jobTitle = ""
var jobDescription = ""
var dict:[String: AnyObject] = ["jobTitle": "jobTitle", "jobDescription": "jobDescription"]
var tArray = [[String: AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for var i = 0; i < 3; ++i {
jobTitle = "job1"
jobDescription = "Desc1"
dict["jobTitle"] = "job1"
dict["jobDescription"] = "Desc1"
tArray.append(dict)
}
println("\(tArray)")
}
}
Like such, where you have more than one value associated with each key:
let jobnames = ["j1", "j2", "j3"]
let jobdescs = ["d1", "d2", "d3"]
var dict : [String:[String]] = [:]
for index in 0..<3 {
if nil == dict["jobTitle"] { dict["jobTitle"] = [] }
if nil == dict["jobDesc" ] { dict["jobDesc" ] = [] }
dict["jobTitle"]!.append(jobnames[index])
dict["jobDesc" ]!.append(jobdescs[index])
}
Here is the output:
You call the same assignmenta such as
jobTitle = "job1"
at every iteration of the loop. Of course the variable will always contain the same value. The same is true for dict. It is an ivar, so you keep overwriting it.
What you want is to create a new collection of type [String: AnyObject] to add to your array.
let newDict:[String : AnyObject] = [titleKey : titleText,
descriptionKey : descriptionText]
tArray.append(newDict)

Resources