Swift 2 - Create a array of arrays - arrays

Im trying to make an array with multiple arrays inside of it.
Im using CloudKit to get the data.
import UIKit
import CloudKit
var questionsCount = 0
var questionsArray = [String]()
class hvadvilduhelstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//firstfield.setTitle("Klik her for at starte!", forState: .Normal)
//secondfield.setTitle("Klik her for at starte!", forState: .Normal)
firstfield.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
firstfield.titleLabel?.textAlignment = NSTextAlignment.Center
secondfield.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
secondfield.titleLabel?.textAlignment = NSTextAlignment.Center
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "Questions", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for entry in results! {
let firstOne = [entry["Question1"] as! String]
let secondOne = firstOne + [entry["Question2"] as! String]
let thirdOne = secondOne + [String(entry["Question1Rating"] as! Int)]
let fourthOne = thirdOne + [String(entry["Question2Rating"] as! Int)]
let fithOne = fourthOne + [String(entry["Reports"] as! Int)]
questionsArray = questionsArray + fithOne
print(questionsArray)
}
}
else {
print(error)
}
}
}
Using previous code I am getting this in the console output:
["Dette er en test1", "Dette er en test2", "0", "0", "0", "test2", "test2", "0", "0", "0"]
instead of this (which is the output i want):
[["Dette er en test1", "Dette er en test2", "0", "0", "0"], ["test2", "test2", "0", "0", "0"]]
I simple can't figure out how to do this. My plan was to get a lot of records and put them inside of this single, huge array (to make it easy to use the 'value') Is there an easier/better way to do this?
Sorry for my english, not my native language.
Thanks for your help!

When you have a problem like this, make a Playground and experiment and do a little thinking. Here is what you are doing, in essence:
var arr = [String]()
for _ in (1...3) {
let first = ["Mannie"]
let second = first + ["Moe"]
let third = second + ["Jack"]
arr = arr + third
}
arr // ["Mannie", "Moe", "Jack", "Mannie", "Moe", "Jack", "Mannie", "Moe", "Jack"]
That isn't what you want, so don't do that. First, as your question title says, you want an array of arrays. Well then, you don't want to end up with a [String]; you just told us that you want a [[String]] (an array of arrays of strings)! So first make that change:
var arr = [[String]]()
Now, when you build your array and insert it into your array of arrays, use the append method (instead of the + operator):
arr.append(third)
Here's the result:
var arr = [[String]]()
for _ in (1...3) {
let first = ["Mannie"]
let second = first + ["Moe"]
let third = second + ["Jack"]
arr.append(third)
}
arr // [["Mannie", "Moe", "Jack"], ["Mannie", "Moe", "Jack"], ["Mannie", "Moe", "Jack"]]
Now go ye and do likewise in your real code.

Try this instead:
import UIKit
import CloudKit
var questionsCount = 0
var questionsArray = [[String]]()
class hvadvilduhelstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//firstfield.setTitle("Klik her for at starte!", forState: .Normal)
//secondfield.setTitle("Klik her for at starte!", forState: .Normal)
firstfield.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
firstfield.titleLabel?.textAlignment = NSTextAlignment.Center
secondfield.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
secondfield.titleLabel?.textAlignment = NSTextAlignment.Center
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "Questions", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for entry in results! {
let firstOne = entry["Question1"] as! String
let secondOne = entry["Question2"] as! String
let thirdOne = String(entry["Question1Rating"] as! Int)
let fourthOne = String(entry["Question2Rating"] as! Int)
let fifthOne = String(entry["Reports"] as! Int)
questionsArray.append([firstOne, secondOne, thirdOne, fourthOne, fifthOne])
print(questionsArray)
}
}
else {
print(error)
}
}
}
}
Notably, questionsArray is now of type [[String]], not just [String], and for each entry, you want to append a new [String]

Related

How to add data inside two arrays inside for loop

I'm trying to add data to array inside for loop and again to array in another for loop.
Its working on first for loo, but in second data is empty. How to fix that
This is how it currently looks inside firestore and you can see scores missing.
this is code:
func updateCourseData() {
var data = ["endTime": Timestamp(date: Date()),
"players": []] as [String : Any]
for i in 0..<players.count {
var playerData = ["playerId": games[i].id,
"scores": []] as [String : Any]
var existingItems = data["players"] as? [[String: Any]] ?? [[String: Any]]()
existingItems.append(playerData)
data["players"] = existingItems
for score in 0..<selectedPage + 1 {
let scoreData = ["hole": games[i].scores[score].hole,
"score": games[i].scores[score].score] as [String : Any]
var existingScores = playerData["scores"] as? [[String: Any]] ?? [[String: Any]]()
existingScores.append(scoreData)
playerData["scores"] = existingScores
}
}
Constants.FirebaseCollection.gamesCollection.document(documentId).updateData(data) { error in
if let error = error {
print(error.localizedDescription)
}
print("Game updated")
}
}

convert nsmanganedobject to array to find sum of array

My code below is trying to take core data from a NSManagedObject append it to an array. The core data element is saved as a string. My code is not compelling. Ideally the code should be able to append code into the array then the array is filled, find the sum of the numbers added together and print them into the viewDidLoad() func.
var itemName : [NSManagedObject] = []
func performAction() {
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Data")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
var retrievedData = [Double]()
for data in result as! [NSManagedObject] {
if let value = data.value(forKey: "ee") as? Double {
retrievedData.append(value)
}
}
let arraySum = retrievedData.reduce(0, +)
print(arraySum)
} catch {
print("Failed")
}
}
I reviewed your code when you will need to change small thing over there. Replace performAction function as per my updated answer.
func performAction() {
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Data")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
var retrievedData = [Double]()
for data in result as! [NSManagedObject] {
if let value = data.value(forKey: "ee") as? String {
retrievedData.append(Double(value) ?? 0)
}
}
let arraySum = retrievedData.reduce(0, +)
print(arraySum)
} catch {
print("Failed")
}
}

Map function explanation

Someone can explain me that piece of code because I can't understand well. I find this code and I can't understand notably this line : Room(dict: $0)
var rooms: [Room] = [] // The globale variable
func refresh() {
let request = URLRequest(url: URL(string: "\(Config.serverUrl)/rooms")!)
NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main, completionHandler: { resp, data, err in
guard err == nil else {
return
}
let rooms = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [[String: AnyObject]]
self.rooms = rooms.map {
Room(dict: $0) // I can't understand this line
}
self.tableView.reloadData()
})
}
My Room struct:
struct Room {
var key: String
var title: String
var cat: String!
init(dict: [String: AnyObject]) {
title = dict["title"] as! String
key = dict["key"] as! String
cat = dict["cat"] as! String
}
init(key: String, title: String, cat: String) {
self.key = key
self.title = title
self.cat = cat
}
func toDict() -> [String: AnyObject] {
return [
"title": title as AnyObject,
"key": key as AnyObject,
"cat": cat as AnyObject
]
}
}
If someone can help me to understand and explain it, thank you
The map function loops over every item in a collection, and applies an operation to each element in the collection.
This piece of code
self.rooms = rooms.map {
Room(dict: $0)
}
is a short form of this.
// `dict` paramater is `$0` in shorter form
self.rooms = rooms.map { (dict : [String: AnyObject]) -> Room in
return Room(dict: dict)
}

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 on Swift: Array to String/TextField Text

I have problem with JSON Array that I want to be display on textfield. JSON is taken from URL. This is JSON structure:
{
description = „This is short decripton”;
);
more-description = (
„this is first line”,
„this is second line”,
„third line”,
„etc”,
„etc”
);
one-more-description = (
„this is first line”,
„this is second line”,
„third line”,
„etc”,
„etc”
);
And this is my code:
import UIKit
class RecipeViewController: UIViewController {
#IBOutlet weak var descriptionTextField: UITextView!
#IBOutlet weak var more-descriptionTextField: UITextView!
#IBOutlet weak var one-more-descriptionTextField: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let urlAsString = "http://JSON-Address.com"
let url = NSURL(string: urlAsString)!
let urlSession = NSURLSession.sharedSession()
let jsonQuery = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
do {
if let jsonDate = data, let jsonResult = try NSJSONSerialization.JSONObjectWithData(jsonDate, options: []) as? NSDictionary {
print(jsonResult)
let jsonDescription = jsonResult["description"] as? String
print("result: \(jsonDescription)")
let jsonMoreDescrp: AnyObject? = jsonResult["more-description"] as? Array<AnyObject>
print("result: \(jsonMoreDescrp)")
let jsonOneMoreDescrp: AnyObject? = jsonResult["one-more-description"] as? Array<AnyObject>
print("result: \(jsonOneMoreDescrp)")
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = jsonDescription
self.more-descriptionTextField.text = jsonMoreDescrp as? String
self.one-more-descriptionTextField.text = jsonOneMoreDescrp as? String
});
}
} catch let error as NSError {
print(error)
}
})
jsonQuery.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
The problem is with jsonMoreDescrp & jsonOneMoreDescrp. Althought I've changed it to String, after running Xcode the result is empty. jsonDescription of course works, but this is just simple string.
I know I'm doing something wrong with Array, but - can you tell me what?
jsonMoreDescrp & jsonOneMoreDescrp are array. so, you can call like this
self.more-descriptionTextField.text = jsonMoreDescrp[indexValue] as? String
self.one-more-descriptionTextField.text = jsonOneMoreDescrp[indexValue] as? String
Hope this will help you.
Try this way, if it not works comment me the error you come across.
self.more-descriptionTextField.text = jsonMoreDescrp[indexValue].stringValue
self.one-more-descriptionTextField.text = jsonOneMoreDescrp[indexValue].stringValue
indexValue is the key of the value you want in the json.
[Updated] As Sudhir noticed there is also error in code, try this to show comma separated strings:
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = jsonDescription
self.more-descriptionTextField.text = (jsonMoreDescrp as? [String])?.joinWithSeparator(",") ?? ""
self.one-more-descriptionTextField.text = (jsonOneMoreDescrp as? [String])?.joinWithSeparator(",") ?? ""
});
Validate JSON structure online before using http://jsonlint.com/
Valid JSON:
{
"description": "This is short decription",
"more-description": [
"this is first line",
"this is second line",
"third line",
"etc",
"etc"
],
"one-more-description": [
"this is first line",
"this is second line",
"third line",
"etc",
"etc"
]
}
try this code, it is much easy to use.
First of all parse all elements of map to the variables and than do what you want with knowing structure of just created variables.
let task = session.dataTask(with: url!) {
(data, response, error) in
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let desc = json["description"] as? String,
let moreDesc = json["more-description"] as? [String],
let oneMoreDesc = json["one-more-description"] as? [String] {
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = moreDesc
self.more-descriptionTextField.text = moreDesc.joinWithSeparator("/n")
self.one-more-descriptionTextField.text = oneMoreDesc.joinWithSeparator("/n")
});
}
} catch let error {
print (error)
}
}
task.resume()
I have not tested it, but it should work. Feel free to ask.

Resources