I'm hoping to pass data of a selected row to a second viewcontroller with segue. The results that fill the first viewcontroller tableview are an array. In the segue I'm using:
if ([[segue identifier] isEqualToString:#"detailSegue"]) {
//
DetailVC *dvc = (DetailVC *)[segue destinationViewController];
NSIndexPath *indexPath = [self.resultsVC indexPathForSelectedRow];
Car *selectedCar = (Car *) [self.results objectAtIndex:indexPath.row];
dvc.currentCar = selectedCar;
When I perform segue I get the error:
[NSKnownKeysDictionary1 carName]: unrecognized selector sent to instance
From the research I've done on this topic I do include something similar to the line:
[fetchRequest setResultType:NSDictionaryResultType]
Which when deleted has helped others. I'll need to keep it for my code.
How can I pass data of the selected row to the second viewcontroller?
Update 8JULY
The code i'm using to construct the array is from a fetchrequest. The array row currently displays an integer and carName.
NSArray* results = [context executeFetchRequest:r error:&error];
NSSortDescriptor* sd = [NSSortDescriptor sortDescriptorWithKey:#"number" ascending:NO];
results = [results sortedArrayUsingDescriptors:#[sd]];
self.results = results;
Is the issue that I'm pointing the segue to search Car* rather than this array output?
Update 12JULY
Following suggestions of Aubada Taljo I removed reference of Car* and add the following to the segue:
dvc.selectedCar = [self.results objectAtIndex:indexPath.row];
and declared NSDictionary in my detailVC.
If you are sure the problem is here, then are you sure self.results contain objects of type Car*?
I would suggest you check in the variables watcher that it contains objects of type Car* because it seems you are requesting the property carName from an object of another type.
Related
I got two arrays from API call,
One is nameArray - which contains recipe names ( menuNameArray = ["pohe","bread","cheese chilli toast"]
And another array - which contains prices of those recipes (menuPriceArray = ["10", "40", "120"].
I have got theses two arrays from API call.
I am displaying both the arrays on the table view & I am searching through the menuNamesArray because I want to search by recipe names.
I am getting recipe names by searching those from menuNameArray. Now I want menuPriceArray to get updated also according to searched menuName Array.
means if I search for "bread" then I must get price value as "40" and accordingly for other names also.
How should I perform such filtering on the second array?
My code Snippet -
//MARK: UISearch result update delegate
func updateSearchResults(for searchController: UISearchController) {
// here arrFilter is the resulting array to sotre searched items from menuNamesArray
arrFilter.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (menuNamesArray as NSArray).filtered(using: searchPredicate)
let result = menuPriceArray.firstIndex(of: array.startIndex)
arrFilter = array as! [String]
self.tblSearch.reloadData()
//here now I got the searched menu names, Now I want prices for searched menu names from menuPrice Array..
}
Never use multiple arrays as data source.
Swift is an object oriented language. Take advantage of it.
Create a struct
struct Menu {
let name : String
let price : Double
}
and a data source array
var menues = [Menu]()
Filter the array by name and get the price, pretty easy and straightforward
if let foundMenu = menues.filter(where: {$0.name == "bread"}) {
print(foundMenu.price)
}
You can merge the two arrays into one array of dictionary elements.
var allCards = [CCard]
var cardsMade = 0
^^ is outside of my view controller class as to make it global and accessible in all other view controller files.
in another view controller i have
#IBAction func saveInfo(sender: UIButton) {
let a = CCreature(n: cName!, e: cExpansion, ec: cEnergy!, tc: cTurnCount!,
ef: cEffect!, at: cStrength!, ht:cHealth!, sp: cSpeed!, sb: false)
allCards.append(a)
cardsMade++}
so when the saveInfo button is pressed, i put all the information the user has typed (which were in UITextFields, and then saved into the corresponding vairables cEnergy etc..) into a subclass of CCard called CCreature, with all of the information. After I create the instance of the class, i am trying to store in the array allCards. I am getting an error on the line:
var allCards = [CCard]
Expected member name or constructor call after type name
And in the line where a is appended to the array i am getting this error:
Cannot convert value of type 'CCreature' to expected argument type 'inout Array < CCard >'
I was also getting this error message before, when my program was compiling:
fatal error: Array index out of range
Any ideas?
As you have it [CCard] is a type declaration, you could use it as:
var allCards : [CCard]
but, that won't actually initialize allCards to be useful, alternatively, you could actually create the array and initialize it using:
var allCards = [CCard]()
Where you're using the default array constructor
It's not the entirety of your example, because you didn't include a lot of the pieces, but stripped down to show usage, would be:
var allCards = [CCard]()
func saveInfo() {
let a = CCreature()
allCards.append(a)
}
I want to be able to save an array, cardImages, that contains UIImages via SwiftyUserDefaults.
Desired Behavior
Here is the exact desired behavior:
Save an array of UIImages to NSUserDefaults via the SwiftyUserDefault library
Retrieve the images later
Code This is stripped down to very little code
var newPhotoKey = DefaultsKey<NSArray>("image")//Setting up the SwiftyUserDefaults Persisted Array
cardImages = [(UIImage(named: "MyImageName.jpg")!)] //This array contains the default value, and will fill up with more
Defaults[theKeyForStoringThisArray] = cardImages //This is the persisted array in which the array full of images should be stored. WHERE THE ERROR HAPPENS
var arrayToRetreiveWith = Defaults[theKeyForStoringThisArray] as! [UIImage] //To Retreive
Error
I get the following error:
Attempt to set a non-property-list object (
", {300, 300}"
) as an NSUserDefaults/CFPreferences value for key image
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object (
", {300, 300}"
) for key image'
Thanks!
The error message is clear actually. UIImage is not a propertylist so you need to change it to a row data first. I'll put example below but FYI saving big data like images using NSUserDefaults is really not recommended. I'd use NSFileManager and put it in the user documents directory. anyway
var newPhotoKey = DefaultsKey<NSArray>("image")
cardImages = [(UIImage(named: "MyImageName.jpg")!)]
var cardImagesRowdataArray: NSData = []
for image in cardImages {
let imageData = UIImageJPEGRepresentation(image, 1.0)
cardImagesRowdataArray.append(imageData)
}
Defaults[theKeyForStoringThisArray] = cardImagesRowdataArray
var arrayToRetreiveWith = Defaults[theKeyForStoringThisArray] as! [NSData]
// here you can use UIImage(data: data) to get it back
If you don't insist on using SwiftyUserDefaults, you can save it in the user documents directory, here is how to do it
func saveImage(image: UIImage){
if let imageData = UIImageJPEGRepresentation(image, 1.0) {
let manager = NSFileManager()
if let docUrl = manager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first{
let uniqueName = NSDate.timeIntervalSinceReferenceDate()
let url = docUrl.URLByAppendingPathComponent("\(uniqueName).jpg")
imageData.writeToURL(url, atomically: true)
}
}
}
The value of a user default must be a property list. A property list is
a string (String or NSString),
an NSData,
a date (NSDate),
a number (NSNumber),
a boolean (also NSNumber),
an array of property lists,
or a dictionary whose keys are strings and whose values are property lists.
A UIImage is none of those, so a UIImage is not a property list and cannot be part of a property list.
You need to convert your image to an NSData to store it in a user default. Since a UIImage contains some properties (like scale and imageOrientation) in addition to raw pixel data, the easiest way to convert a UIImage to an NSData with no loss is by creating an archive:
let cardImage: UIImage? = someImage()
let cardImageArchive: NSData = NSKeyedArchiver.archivedDataWithRootObject(cardImage!)
Now you can store cardImageArchive in a larger property list that you can store as a user default.
Later, when you need to recreate the image from the data, do this:
let cardImageArchive: NSData = dataFromUserDefaults()
let cardImage: UIImage = NSKeyedUnarchiver.unarchiveObjectWithData(cardImageArchive) as! UIImage
My PFUser subclass contains a column which is an array of pointers. When showing the [PFUser currentUser] profile page, the array objects are not included and calling
[[PFUser currentUser fetchIfNeededInBackground]
won't fetch the pointer objects either.
If the column was a single pointer, I could call
[currentUser[#"pointerColumn"] fetchIfNeedInBackground]
but the method's argument is a PFObject and not an Array of Pointers.
I can call fetchIfNeededInBackgroundWithBlock for every object in the array, but that makes many requests for a single column in the PFUser class.
for (PFObject * obj in currentUserArrayOfPointers) {
[obj fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error){
[self.tableView reloadData];
}];
}
Is there a better way to fetch [PFUser currentUser]'s array of pointers column?
(And keep the behavior of "fetchIfNeeded", which avoids making a new query each time if the object was already fetched.)
What you can do is get all the objectIds in your currentUserArrayOfPointers and then do a parse query with this parameter:
NSMutableArray *userObjectIds = [[NSMutableArray alloc] init];
for (PFObject * obj in currentUserArrayOfPointers) {
[userObjectIds add:object.objectId];
}
PFQuery *query = [PFQuery queryWithClassName:#"SomeClass"];
[query whereKey:#"objectId" containedIn:userObjectIds];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error {
...
}];
This way you'll be able to get all the users with one query.
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"]