I have an array of NSManagedObject's and I want to copy them to a new array in order to manipulate them and not save the changes after the user is done.
The array:
var origQuestions: [Questions]?
This is how I retreive the data from CoreData:
self.origQuestions = MainDb.sharedInstance.randomQuestions(entity: "Questions", count: self.questionToShow)
This is what I need in Objective-C, but I want to know how to do so in Swift 4:
NSMutableArray *questionsCopy = [[NSMutableArray alloc] initWithArray:self.origQuestions copyItems:YES];
To translate that Objective-C code into Swift you do:
var questionsCopy = NSArray(array: origQuestions, copyItems:true) as! [Questions]
But since you declared origQuestions as optional, it needs to be:
var questionsCopy = origQuestions != nil ? NSArray(array: origQuestions!, copyItems:true) as? [Questions] : nil
Whether that fully works (Objective-C or Swift) with NSManagedObject or not is another question. See How can I duplicate, or copy a Core Data Managed Object? and its Swift answers for code that specifically covers doing deep copies of NSManagedObject instances.
Related
I have an api that creates a JWT for a logged in user and when I look at the decoded version of the token on jwt.io I get what I expect.
It shows that the data property is [] and it holds the users data when a user is logged in.
Now I am trying to decode this into swift for my iOS app, but the data in the data property comes back as:
(
)
and the type for this is __NSArray0
I can't loop through it or anything - what is a __NSArray0 and how would decode the token properly?
__NSArray0:
__NSArray means it's an NSArray object. It's the "old Objective-C immutable Array type". That's what gives you after decoding an JSON Array with (NS)JSONSerialization if you don't cast it into a Swift Array.
The 0 at the end is to say it's a specific NSArray, it's an NSArray empty, with no object. Why using that? Because in reality, it's a internal version of NSArray that is optimized for zero elements. So don't mind about it.
Since you have a NSArray, typical print of it, is:
(
)
So just cast it as an Array how its supposed type when non-empty to iterate. If you know it's an array of String, cast is as [String] and iterate over it.
It's the OpenStep format. Did you ever tried to read a PBXCodeProj?
Like more yourApp.xcodeproj/project.pbxproj It's there, you see how are printed NSDictionary, NSArray etc in that Format + comments.
In JSON, it's [] to show it's an Array, but in Objective-C the print is different.
Want to reproduce it?
let emptyNSArray = NSArray()
print("emptyNSArray:\n\(emptyNSArray)")
let castedEmptyAsArray = emptyNSArray as [AnyObject]
print("castedEmptyAsArray:\n\(castedEmptyAsArray)")
let nsArray = NSArray(array: ["Hello", "World", "!"])
print("nsArray:\n\(nsArray)")
let castedAsArray = nsArray as [AnyObject]
print("castedAsArray:\n\(castedAsArray)")
let emptyArrayJSON = Data("[]".utf8)
let decodedEmptyArrayDefault = try! JSONSerialization.jsonObject(with: emptyArrayJSON)
print("decodedEmptyArrayDefault:\n\(decodedEmptyArrayDefault)") //If you don't cast, it's by default a NSArray
let decodedEmptyArrayCasted = try! JSONSerialization.jsonObject(with: emptyArrayJSON) as! [AnyObject]
print("decodedEmptyArrayCasted:\n\(decodedEmptyArrayCasted)")
Output:
$>emptyNSArray:
(
)
$>castedEmptyAsArray:
[]
$>nsArray:
(
Hello,
World,
"!"
)
$>castedAsArray:
[Hello, World, !]
$>decodedEmptyArrayDefault:
(
)
$>decodedEmptyArrayCasted:
[]
I am using a UISearchController in my updateSearchResultsForSearchController
I am filtering an array of usernames with a NSPredicate:
self.filteredChats.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (self.gruppenNamen as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.filteredChats = array as! [String]
Is there a way to store the indexPath of each filtered element?
I need to know that in order to display my cells correctly, since I am also using arrays for images and other data.
Let's says that you have gruppenNamen and gruppenImages. You want to keep them synchronized.
I would strongly suggest that you create a custom class with a property name, and a property image.
Since you seem to not want that, you could use indexesOfObjectsPassingTest: and objectsAtIndexes:. I don't use Swift, so I'll code in Objective-C, but it should be easily translated.
NSIndexSet *indexes = [self.gruppenNamen indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return [(NSString *)obj rangeOfString:searchController.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
}];
self.filteredChat = [self. gruppenNamen objectsAtIndexes:indexes];
self.filteredImages = [self.gruppenImages objectsAtIndexes:indexes];
I used rangeOfString:options for the equivalent of contains[c] of your predicate. You could use a NSPredicate here too.
I am currently struggling with obtaining a value from an array inside an array of dictionaries. Basically I want to grab the first "[0]" from an array stored inside an array of dictionaries. This is basically what I have:
var array = [[String:Any]]()
var hobbies:[String] = []
var dict = [String:Any]()
viewDidLoad Code:
dict["Name"] = "Andreas"
hobbies.append("Football", "Programming")
dict["Hobbies"] = hobbies
array.append(dict)
/// - However, I can only display the name, with the following code:
var name = array[0]["Name"] as! String
But I want to be able to display the first value in the array stored with the name, as well. How is this possible?
And yes; I know there's other options for this approach, but these values are coming from Firebase (child paths) - but I just need to find a way to display the array inside the array of dictionaries.
Thanks in advance.
If you know "Hobbies" is a valid key and its dictionary value is an array of String, then you can directly access the first item in that array with:
let hobby = (array[0]["Hobbies"] as! [String])[0]
but this will crash if "Hobbies" isn't a valid key or if the value isn't [String].
A safer way to access the array would be:
if let hobbies = array[0]["Hobbies"] as? [String] {
print(hobbies[0])
}
If you use a model class/struct things get easier
Given this model struct
struct Person {
let name: String
var hobbies: [String]
}
And this dictionary
var persons = [String:Person]()
This is how you put a person into the dictionary
let andreas = Person(name: "Andreas", hobbies: ["Football", "Programming"])
persons[andreas.name] = Andreas
And this is how you do retrieve it
let aPerson = persons["Andreas"]
i'm updating my app to Swift 2.. lots of errors uff.. anyway i'm trying to read a store array in NSuserDefaults, in swift 1 worked but now i get nil error with EXC_Breakdown. i don't know how to fix that...
this is how i read it:
var DescriptionArray = save.objectForKey("NewsDescriptions")! as! NSArray
this i how i save it (Description is the array):
var SaveDescription = save.setObject(Description, forKey: "NewsDescriptions")
save.synchronize()
Here is an example of how you can store data into NSUserDefault in Swift 2.0. It is very similar to Objective-C concept, only different syntax.
Initialize your NSUserDefault Variable:
let userDefaults = NSUserDefaults.standardUserDefaults()
Initialize what type of data to save: In your case you used objectForKey, even though that should work, it's better to be more specific about your code.
var DescriptionArray = userDefaults.arrayForKey("NewsDescriptions")
Save your data:
userDefaults.setObject(Description, forKey: "NewsDescriptions")
Then you can synchronize to process the saving faster.
userDefaults.synchronize()
Here is an example with Swift 2:
func saveArray(value: NSArray) {
NSUserDefaults.standardUserDefaults().setObject(value, forKey:"NewsDescriptions")
NSUserDefaults.standardUserDefaults().synchronize()
}
func readArray() -> NSArray {
return NSUserDefaults.standardUserDefaults().arrayForKey("NewsDescriptions")!
}
So, I'm learning how to get data from DB with JSON and then put the data on some array. Problem accours on last line, citiesArray.addObject(City()), when I need to put all data from object city (id, name, state,...) into array.
I was looking line by line with compiler, and basically everything is fine except that at the end, my array is still empty (its value is nil)?
for (var i=0;i<jsonArray.count;i++){
//Create city objec
var cID: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("id") as NSString
var cName: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityName") as NSString
var cState: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityState") as NSString
var cPopulation: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("cityPopulation") as NSString
var cCountry: AnyObject? = jsonArray.objectAtIndex(i).objectForKey("country") as NSString
//add city obj (i have City class) to city array
var city = City()
city.cityID = cID as NSString
city.cityName = cName as NSString
city.cityState = cState as NSString
city.cityPopulation = cPopulation as NSString
city.cityCountry = cCountry as NSString
citiesArray.addObject(City())
}
A couple of issues:
You suggested that you were trying to add the city with the following line of code:
citiesArray.addObject(City())
The City() construct will instantiate a new, blank City object. So that line of code would, best case scenario, add a blank City object to your array, which is not what you intended.
When you add the city to your citiesArray, you should simply:
citiesArray.addObject(city)
You say you've defined your citiesArray like so:
var citiesArray: NSMutableArray!
You also need to instantiate an object for this variable (i.e. create an object to which this variable will now point), e.g.:
citiesArray = NSMutableArray()
You are reporting, though, that at the end of this loop, that citiesArray is nil. Really?!? But if you tried to call the addObject method and citiesArray was nil, you could have received a fatal error: "unexpectedly found nil while unwrapping an Optional value".
So, if citiesArray was nil, then jsonArray must have been empty, too. Or for some reason you didn't even get to this loop. I would suggest (a) logging jsonArray; and (b) log or put breakpoint inside this loop and confirm you're even getting in here like you think you are.
Also, check the timing of this (i.e. make sure your statement logging citiesArray is actually taking place after this routine that populates it). I know that sounds crazy, but if you are retrieving the data from some network resource asynchronously, you could have some timing related issues.
Since you're writing Swift code, you might consider using Swift arrays. For example, define your array variable as
var citiesArray: [City]!
And instantiate it with:
citiesArray = [City]()
And add objects to it with:
citiesArray.append(city)
I am pretty sure you need to use the append function:
citiesArray.append(city)
or
if you want to append at the start of the array
citiesArray.insert(city, atIndex: 0)
instead of
citiesArray.addObject(City())
here is a little example: Syntax might not be 100% not on comp with xcode right now.
var strA:String = "apple"
var strB:String = "pineapple"
var strArr = ["kiwi", "mango", "lime"]
strArr.append(strA)
println(strArr.count) //4 ["kiwi", "mango", "lime", "apple"]
citiesArray.insert(strB, atIndex: 0)
println(strArr.count) //5 ["pineapple", "kiwi", "mango", "lime", "apple"]