Swift Collection <__NSCFSet: 0x161174110> was mutated while being enumerated - arrays

I understand that I can't add or remove an element from an array while it's being enumerated, but...I'm not! I think I have narrowed down where the crash happens but it doesn't make any sense to me.
func sendToCloud() {
for quoteNumber in newQuotes {
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Quotes")
let predicate = NSPredicate(format: "quoteNumber == %#", quoteNumber)
fetchRequest.predicate = predicate
fetchRequest.fetchLimit = 1
do {
//The next two lines is where the crash happens...
quotes = try context.fetch(fetchRequest)
let currentQuote = quotes.first as! Quotes
//-------------------------------------------
prepRecordForCoreData(obj: currentQuote, recordName: currentQuote.ckrecordname!, recordType: "Quotes")
repRecordForCoreData(obj: currentQuote.customer!, recordName: currentQuote.ckrefcustomer!, recordType: "Customers")
} catch let error as NSError {
print("ERROR SAVING TO CLOUD", error)
}
}
//clear array
newQuotes = []
coreData.saveContext { (success) -> Void in
if success {
AppData.uploadRecords()
}
}
}
Just in case...
func prepRecordForCoreData(obj: SignatureManagedObject, recordName: String, recordType: String) {
let zone = CKRecordZone(zoneName: Contstants.Strings.zoneName)
let id = CKRecord.ID(recordName: recordName, zoneID: zone.zoneID)
let record = CKRecord(recordType: recordType, recordID: id)
let coder = NSKeyedArchiver(requiringSecureCoding: true)
record.encodeSystemFields(with: coder)
let metadata = coder.encodedData
obj.ckmetadata = metadata
obj.ckrecordname = recordName
obj.ckupload = true
}

Related

How can I merge 2 dictionaries into one array?

My JSON data look like this image below. Now I wanna merge the value of Shop Type and Promotion into one to use as collection view data. How can I do that?
I just filter the response data from the server like this:
var dataBanDau: [SDFilterModel] = []
var quickData: [SDFilterModel] = []
let filters: [SDFilterModel] = data
self.filterEntries = filters
//let nsarray = NSArray(array: self.filterEntries! , copyItems: true)
// self.filterEntriesStoreConstant = nsarray as! Array
self.dataBanDau = filters
for i in 0..<self.dataBanDau.count {
if self.dataBanDau[i].search_key.count == 0 {
self.quickData.append(self.dataBanDau[i])
}
}
self.quickData = self.quickData.filter {
$0.type != "range"
}
DispatchQueue.main.async {
//Note: Reload TableView
self.quickFilterCollection.reloadData()
completed(true)
}
}
the class SDFilterModel:
class SDFilterModel: DSBaseModel {
var name = String()
var type = String()
var is_expanded = Int()
var search_key = String()
var filterEntries : [SDFilterModel]?
override func copy(with zone: NSZone? = nil) -> Any {
// This is the reason why `init(_ model: GameModel)`
// must be required, because `GameModel` is not `final`.
let copy = SDFilterModel(dict: self.dictionary)
if let arrAttribute = NSArray(array: self.value , copyItems: true) as? [AttributeValueModel] {
copy.value = arrAttribute
}
return copy
}
override init(dict: Dictionary<String, Any>) {
super.init(dict: dict);
value = self.valueParse()
name = dict.getString(forKey: "name")
type = dict.getString(forKey: "type")
search_key = dict.getString(forKey: "search_key")
is_expanded = dict.getInt(forKey: "is_expanded")!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var value: [AttributeValueModel] = [];
func valueParse()-> [AttributeValueModel] {
guard let childs = (self.dictionary["value"]) as? [Dictionary<String, AnyObject>]
else { return [] }
var output: [AttributeValueModel] = [];
for aDict in childs {
let item = AttributeValueModel(dict:aDict);
// if type == .Range && item.option_id == "0" {
// item.setRangeOptionID(aValue: item.option_name!)
// }
//
output.append(item);
}
return output;
}
Let be Assume you have let myArray = [1,2,3,4,5,6,7,8]
Now you wanted to square of each and every element in the array,
With for loop you do like this
for item in myArray {
print(item * item)
}
Now assume item = $0
With for map you jus do
myArray.map({ $0 * $0 })
Both will gave same output.
map : Use to do same operation on every element of array.
flatmap : It is used to flattern the array of array.
let myArr = [[1,2,3],[4,5,6,7]]
and you want o/p as [1,2,3,4,5,6,7]
So can get above output with myArr.flatMap({$0})
Now back to your question.
let reqArray = myModel.data.map({ $0.value }).flatMap({ $0 })
First, map gaves you array-of-array of key value but you need a single array, so for that you need to use flatmap.
You can take ref : https://medium.com/#Dougly/higher-order-functions-in-swift-sorted-map-filter-reduce-dff60b5b6adf
Create the models like this
struct Option {
let name: String
let searchKey: String
let id: String
}
struct Model {
let type: String
let name: String
let isExpanded: Bool
let value: [Option]
}
You should get the options array values and join all the arrays
let models:[Model] = //...
let collectionViewArray = models.map { $0.value }.reduce([Option](), +)
Using for loop
var collectionViewArray = [Option]()
for model in models {
collectionViewArray.append(contentsOf: model.value)
}

How can I remove whole dictionary in nested array at specific index after filter some specific value

I have API response with nested array . But I can't understand how can I remove whole Dict by filtering the value .
This is the response screenshot
https://imgur.com/XIDyfYX
here is the json Resonse :- https://del.dog/lofavofogo.json
I have tried this but I don't know how to get filter nested value and remove whole dict at specific index
How to remove pairs from dictionary at specific index - Swift?
I want to remove the dict where section name are "NA"
Here is the code :-
Model Class For API Response :-
class filterclass: NSObject {
var classesID : String?
var classname : String?
var section = [filterSections]()
init(json: [String: Any]) {
if let classname = json["class"] as? String {
self.classname = classname
}
if let classesID = json["classesID"] as? String {
self.classesID = classesID
}
print("classname",classname)
if let evUserGoing = json["classsection"] as? [[String: Any]] {
if self.section.count > 0
{
self.section.removeAll()
}
for evUser in evUserGoing {
// print("evUser",evUser)
let userGoing = filterSections(json: evUser)
self.section.append(userGoing)
}
for sec in section {
let section = sec.secctionname
let setionID = sec.sectionID
}
}
}
}
class filterSections: NSObject {
var sectionID : String?
var secctionname : String?
var isSelctedSection : Bool = false
init(json: [String: Any]) {
if let sectionID = json["sectionID"] as? String {
self.sectionID = sectionID
}
if let secctionname = json["section"] as? String {
self.secctionname = secctionname
}
print("sectioname",secctionname)
}
}
API POST Method TO hit API :-
func getClassSectionAPI() {
if ReusableClass.sharedInstance.isNetworkAvailable() == true
{
ReusableClass.sharedInstance.showActivityIndicator()
let UUid = LoginUserInfo.sharedInstance.uuid!
let dictionary = ["uuid":UUid,"device_id":devicetoken,"school_id":LoginUserInfo.sharedInstance.schoolId!, "user_type":LoginUserInfo.sharedInstance.usertype!]
print(dictionary)
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(dictionary) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
// print(jsonString)
let cipher:String = CryptoHelper.encrypt(input:jsonString)!;
let NewEncryption = "data=\(cipher)"
print(NewEncryption)
let hmac_md5 = cipher.hmac(algorithm: .sha512, key: kHMACKey)
print("hmac",hmac_md5)
UserDefaults.standard.set(hmac_md5, forKey: Headerkey)
Singleton.sharedInstance.getWebservicesverify(params: NewEncryption, Methodname: KFilterClassSection, data: Stringnil)
{ (result) in
DispatchQueue.main.async {
ReusableClass.sharedInstance.hideActivityIndicator()
}
if result != nil
{
do {
let jsonData = try JSONSerialization.data(withJSONObject: result)
if let json = String(data: jsonData, encoding: .utf8) {
let Dict = function.convertToDictionary(text: json)! as NSDictionary
guard let data = Dict[KData] as? String
else
{
return
}
self.baseDict = data
}
}
catch {
}
guard let output = CryptoHelper.decrypt(input:self.baseDict)
else
{
return
}
print(output)
let mainDict = function.convertToDictionary(text: output)! as NSDictionary
let status = mainDict[KStatus] as! NSInteger
if(status == 1)
{
DispatchQueue.main.async {
print("Main dict",mainDict)
guard let messageArray = mainDict["data"] as? [[String: Any]] else{
return
}
if self.arrayClasSection.count > 0
{
self.arrayClasSection.removeAll()
}
print("Main dict",messageArray)
for arr in messageArray {
let obj = filterclass.init(json: arr)
if let index = self.arryFilterTemperary.index(where: { $0.classname == obj.classname }) {
// let filtered = self.arryFilterTemperary.filter { $0.classname == "NA" }
obj.section = self.arryFilterTemperary[index].section
self.arrayClasSection.append(obj)
for sec in self.arryFilterTemperary[index].section {
let section = sec.sectionID
let sectionName = sec.secctionname
self.NASection = sec.secctionname!
print(self.NASection)
self.selectedNASectionID = sec.sectionID!
// let test = self.arryFilterTemperary[index].section.filter { !$0.value.contains("") }
// print(test)
}
}
else
{
self.arrayClasSection.append(obj)
}
}
ReusableClass.sharedInstance.hideActivityIndicator()
self.tableFilter.reloadData()
}
}
I want to append the data to array but before appending I want to
filter that "NA" value dict from the array
Since this is your first question I go to some greater length in answering it than usual. Playgrounds are an exceptional way to demonstrate your problem, so you should always try to compose your questions in a form of one. I will post my answer directly from the Playground I have done.
With that out of the way lets get to the question. Your main problem seems to be that you tried an ill fated JSONSerialization "shortcutt" route. This looks cheap from the outside, but working with the unavoidable optionality of a [String:Any] comes at a high cost in a language like Swift. The way to go is the brilliant Codable protocol, at least in my opinion. Once you define your data structure properly Xcode has so much more possibilities to guide you through the APIs that writing your filter code becomes a piece of cake.
Enough of the ranting, let's get to the pizza.
import UIKit
let dataStr = """
{
"status":1,
"message":"Class and sections list",
"data":[
{
"classsection":[
{
"section":"A",
"sectionID":"1",
"classesID":"1"
},
{
"section":"B",
"sectionID":"3",
"classesID":"1"
}
],
"class":"First",
"classesID":"1"
},
{
"classsection":[
{
"section":"A",
"sectionID":"2",
"classesID":"2"
},
{
"section":"B",
"sectionID":"7",
"classesID":"2"
}
],
"class":"Second",
"classesID":"2"
},
{
"classsection":[
{
"section":"A",
"sectionID":"20",
"classesID":"15"
}
],
"class":"Third",
"classesID":"15"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"33",
"classesID":"22"
}
],
"class":"Pre Nursery",
"classesID":"22"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"34",
"classesID":"23"
},
{
"section":"A",
"sectionID":"35",
"classesID":"23"
},
{
"section":"B",
"sectionID":"36",
"classesID":"23"
},
{
"section":"C",
"sectionID":"37",
"classesID":"23"
}
],
"class":"Fourth four",
"classesID":"23"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"38",
"classesID":"24"
}
],
"class":"Fifth",
"classesID":"24"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"39",
"classesID":"25"
}
],
"class":"sixth 6th",
"classesID":"25"
}
]
}
"""
struct Section: Codable {
let section, sectionId, classesId: String
enum CodingKeys: String, CodingKey {
case sectionId = "sectionID"
case classesId = "classesID"
case section
}
}
struct Class1: Codable {
let classsection: [Section]
let clazz, classesId: String
private enum CodingKeys: String, CodingKey {
case classsection
case clazz = "class"
case classesId = "classesID"
}
}
struct Response: Codable {
let status: Int
let message: String
let data: [Class1]
func filterSections(notMatching filterVal: String) -> Response {
let filteredData = data.map { (clazz) -> Class1 in
let filteredSections = clazz.classsection.filter { (sect) -> Bool in
sect.section != filterVal
}
return Class1(classsection: filteredSections, clazz: clazz.clazz, classesId: clazz.classesId)
}
return Response(status: status, message: message, data: filteredData)
}
}
let jsonData = dataStr.data(using:.utf8)!
do {
let res = try JSONDecoder().decode(Response.self, from: jsonData)
let filteredResponse = res.filterSections(notMatching: "NA")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
print(String(data:try encoder.encode(filteredResponse), encoding: .utf8)!)
} catch {
print(error)
}
As you can see your data structure is easily defined and the filtering code is really easy to understand once you wrap your head around the lambdas (which you should). The playground will output nicely formatted JSON as an answer, this way it is easy to check that your code does the right thing without all the messy parts of asynchronous communication (which are still nicely done in Swift).
Here's my last tipp of the day: Always try to isolate your problem as much as possible if you post a question on StackOverflow. I think your question carried too much legacy, you should whittle it down for the next one. This will improve your chances for a quick answer.

Parsing JSON array to label

I am trying to parse the JSON below (actual data is 20x the format listed)
{
message = "";
result = (
{
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Created = "2017-06-06T01:22:35.727";
High = "5.44e-05";
Last = "4.69e-05";
Low = "4.683e-05";
MarketName = "BTC-1ST";
OpenBuyOrders = 293;
OpenSellOrders = 4186;
PrevDay = "4.76e-05";
TimeStamp = "2018-02-20T00:00:31.863";
Volume = "662575.93818332";
},
This is the code that I have right now. It successfully prints the value "Last" to the console but when I incorporate the Dispatch.Queue, I get a Thread 1: signal SIGBRT not printing the value to the label.
let myJson = try JSONSerialization.jsonObject(with: content) as! [String:Any]
if let info = myJson["result"] as! [[String:Any]]?
{
for i in 0..<20 {
if i == 1
{
if let dict = info[i] as? [String:Any]
{
if let price = dict["Last"]
{
print(price)
//DispatchQueue.main.async
//{
// self.label1.text = price as String
//}
}
}
}
Any help is greatly appreciated!
Most likely your self.label1 outlet isn't connected. Fix that connection.
You should also update the if let that gets the value for the "Last" key as follows:
if let price = dict["Last"] as? String{
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
}
There is some other cleanup you can do as well:
if let myJson = try JSONSerialization.jsonObject(with: content) as? [String:Any] {
if let info = myJson["result"] as? [[String:Any]] {
for (index, dict) in info.enumerated() {
if index == 1 {
if let price = dict["Last"] as? String {
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
} // else no "Last" or not a String
}
}
} // else "result" doesn't contain expected array of dictionary
} // else content isn't a valid JSON dictionary
Avoid all of those forced casts. Especially avoid force casting to an optional.
JSON doesn't use the = sign or the semicolon. Change every = to a colon and every semicolon to a comma, so that
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Becomes
Ask: "4.8e-05",
BaseVolume: "32.61025363",
Bid: "4.695e-05",

Look through all records for a specific attribute and see the highest value

Ok, so I have an app that is designed for roleplaying. I have a guide that guides the user to creating the character. So the first thing the user has to do is put the character number. So I want it to search all the records for the attribute I have called characternumber and see what the largest number is.
Example: Lets say I have 5 characters. with character numbers 1,2,3,4,5. I want to cycle through all the records and see that 5 is the biggest number than automatically place a 6 in the character number text field.
This is what I have so far:
#IBOutlet var societyNumberTxt: UITextField!
#IBOutlet var characterNumberTxt: UITextField!
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var characters: [NSManagedObject] = []
var societyNum: [NSManagedObject] = []
var charNum: [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
//1
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
//2
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Characters")
//3
do {
societyNum = try managedContext.fetch(fetchRequest)
let entityDescription = NSEntityDescription.entity(forEntityName: "Characters", in: managedObjectContext)
let request: NSFetchRequest<Characters> = Characters.fetchRequest()
request.entity = entityDescription
var results = try managedObjectContext.fetch(request as! NSFetchRequest<NSFetchRequestResult>)
if societyNum.count > 0
{
let match = results[0] as! NSManagedObject
societyNumberTxt.text = (match.value(forKey: "societynumber") as? String)!
print(match)
if (match.value(forKey: "characternumber") != nil)
{
self.charNum = match.value(forKey: "characternumber") as! [String]
print(self.charNum)
}
else
{
print("empty array")
characterNumberTxt.text = "1"
}
}
else
{
societyNumberTxt.placeholder = "Society # not set"
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
I am not sure how to cycle through every record and check the attribute and place in the array. I have tried something like this:
var i = 0
for i in results
{
var match = results[i] as? NSManagedObject
charNum[i] = match
}
I get the error:
cannot subscript a value of type '[Any]' with an index of type 'Any'
Now to test my code for the if statement:
if (match.value(forKey: "characternumber") != nil)
{
self.charNum = match.value(forKey: "characternumber") as! [String]
print(self.charNum)
}
It returned and error:
Could not cast value of type 'NSTaggedPointerString' (0x108578d10) to 'NSArray' (0x108578dd8).
Am I even on the right past?
Adjust your fetch request with a SortDescriptor instead of finding the highest characterNumber manually:
...
//2
// get all characters ...
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Characters")
// ... sorted by characternumber in acending order
let sortDescriptor = NSSortDescriptor(key: "characternumber", ascending: true)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
//3
do {
let characters = try managedContext.fetch(fetchRequest) as! [Characters]
if let highestCharacterNumber = characters.last?.characternumber {
characterNumberTxt.text = String(highestCharacterNumber + 1) // assuming characternumber is of type Int
} else {
characterNumberTxt.text = "1"
}
} ...

json missing fields swift

So I have a function that pulls data from a json file and parses it. Its throwing me a nil error because some of the json entries don't have the "colors" field/array. How would i account for this and put in "ERROR" as the text for the ones that didn't.
func getData2(){
let dataPath = NSBundle.mainBundle().pathForResource("cardata", ofType: "json")
if let JSONData = NSData(contentsOfFile: dataPath!)
{
do
{
if let dictionariesArray = try NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions()) as?
[[String: AnyObject]]
{
for dictionary in dictionariesArray
{
let name = dictionary["name"] as! String
let type = dictionary["type"] as! String
let text = String(dictionary["text"])
if let printingsArray = dictionary["colors"] as? [String]
{
let printingsString = String(printingsArray.joinWithSeparator("-"))
nameColor[name] = printingsString
}
nameType[name] = type
nameText[name] = text
}
}
}
catch
{
print("Could not parse file at")
}
}
struct Card {
let name: String
let type: String
let colorr: String
let textt: String
init(name: String, type: String, textt: String, colorr:String) {
self.name = name
self.type = type
self.textt = textt
self.colorr = colorr
}
}
var goodCard = [Card]()
for (cardName, cardType) in nameType {
let cardText = nameText[cardName]!
let cardColor = nameColor[cardName]! //fatal error: unexpectedly found nil while unwrapping an Optional value
goodCard.append(Card(name: cardName, type: cardType, textt: cardText, colorr: cardColor))
}
if typee != "" {
let redDogs = goodCard.filter {$0.type == typee}
print(redDogs)
}
You should avoid using the forced unwrapping operator ! whenever possible. If you use it and the Optional is nil then when you use the variable it will throw an exception. Instead use optional binding to unwrap the value:
// optional binding
if let cardColor = nameColor[cardName] {
// do something with the value
}

Resources