Unable to use AnyObject in Swift - ios

I don't understand an inch of how the AnyObject type in Swift is supposed to work. I am loading a Plist file into a NSDictionary instance in my Swift code (not shown here). Later I try to use some of the values from the Plist file in a UIPickerView:
// Trying to extract the first fruit
let fruitKeys = fruits.allKeys
let fruitKey = fruitKeys[0]
// This is another NSDictionary
let fruit = fruits.objectForKey(fruitKey)
// Getting a property of a fruit
let nutritions = fruit.objectForKey("nutritions")
let nutritionKeys = nutritions.allKeys
However I am not able to get the keys of a fruit by calling nutritions.allKeys. I get Could not find member allKeys. However, which part of the documentation have I misunderstood? I read that you can call any objective c method on an instance of AnyObject. Why do I need to cast or to some other magic here?
Should I cast everything to their real types? Or should I use AnyObject??

In short, yes you would generally want to cast to your defined type, here's how I would write it:
let fruitKeys = fruits.allKeys as [String]
let fruitKey = fruitKeys[0]
let fruit = fruits[fruitKey] as NSDictionary
let nutritions = fruit["nutritions"] as NSDictionary
let nutritionKeys = nutritions.allKeys
As I already mentioned in my comment, a possible change to your code would be:
let fruitKeys = fruits.allKeys
let fruitKey = fruitKeys[0]
let fruit = fruits.objectForKey(fruitKey)
let nutritions = fruit.objectForKey("nutritions")
let nutritionKeys : AnyObject? = nutritions.allKeys
I omitted downcasting every value because I saw it as pointless, so you might encounter some warnings, but it will work.

Related

Unable to change ui label in swift

I am trying to make a weather app. the issue I am having is after I get the data parsed out I try to change the UILabel to equal the data that came back example.
if let weather = item["weather"] as? NSArray{
if let value = weather[0] as? NSDictionary{
if let description = value["description"] as? String{
print(description)
}
instead of printing the description I want to change the content of the UI Label like this
conditionlabel.text = description
but I get this error Reference to property 'Condition' in closure requires explicit 'self.' to make capture semantics explicit.
however, every time I try the self. in front it does not print my data and something else happens. Any help would be much appreciated as I am new to this
Create an optional variable in controller that has you UILabel:
var descriptionText: String?
Now when you parse data, assign value to this variable
if let description = value["description"] as? String{
descriptionText = description
}
After data is parsed assign this value to the label
self.conditionlabel.text = descriptionText
I think what you need to do here is use self.conditionlabel.text = description (that is, the use of self is for the UILabel rather than description - my guess is that you were using self.description which gives you a description of the view controller.)
EDIT:
To overcome the threading issue, wrap the code like this:
DispatchQueue.main.async { [weak self] in
self?.conditionlabel.text = description
}

Type any has no subscript error in swift 3

if let name = property["Name"] as? String,
let latitude = property["Latitude"] as? NSNumber,
let longitude = property["Longitude"] as? NSNumber,
let image = property["Image"] as? String {
// To learn how to read data from plist file, check out our Saving Data
// in iOS Video Tutorial series.
// Code goes here
}
When I converted my code to current swift version, I am facing 'Type any has no subscript error'. I am fairly new to swift and stuck at this point. Saw other related posts, but no where I could find a solution for this. Please help.
I poured over the many questions with duplicate titles and couldn't find one that clearly covered your case, so I'm going to explain what is going on.
Your variable property is clearly declared as type Any, which is a variable that can hold any type. The error message is telling you that you can't use subscripting [] with it. It is clear that you believe that it is a Dictionary with a key that is a String and a value that can be anything. In Swift 3, anything is typed Any. So your property is expected to be [String : Any]. If you cast property to [String : Any], then you will be able to use [] with it.
The first thing you should do is attempt to cast property to [String : Any] and then proceed if that works:
if let property = property as? [String : Any],
let name = property["Name"] as? String,
let latitude = property["Latitude"] as? NSNumber,
let longitude = property["Longitude"] as? NSNumber,
let image = property["Image"] as? String {
// To learn how to read data from plist file, check out our Saving Data
// in iOS Video Tutorial series.
// Code goes here
}

Cannot subscript a value of type anyobject

I've currently upgraded to the new Xcode 7, and the following code never had any errors with swift 1.2, but now its telling me that :
Cannot subscript a value of type any object
var imageArray : NSArray = []
let url = NSURL(string: (self.imageArray[indexPath.row][0] as? String)!)
I know its about [0] but how do i rewrite it to be accepted ?
OK, so first you are using an NSArray. You can drop that and make everything much easier.
In Swift always use strong typing where possible. Avoid Any and AnyObject when they are not needed. (They are VERY RARELY needed).
The error is happening because you're not telling the code what is actually in the imageArray.
Also, imageArray tells me the array is full of images. Name your variables more descriptively. imageUrlStringArray or arrayOfImageUrlArrays. Something more descriptive anyway.
Declare imageArray like...
var imageArray = [[String]]()
This tells the compiler that imageArray is a 2D array with Strings at the second level.
Now you can create your URL easily...
guard
let urlString = imageArray[indexPath.row].first,
let url = NSURL(string: urlString)
else { // Handle the inability to create a URL }
// Do something with the url

Swift: Cast from 'Ride' to unrelated type 'NSDictionary' always fails

I'm building my first iOS app using Swift 2.0 and I'm running in to the following error:
Cast from 'Ride' to unrelated type 'NSDictionary' always fails
at this line:
if let rowData: NSDictionary = ride as? NSDictionary,
Just below my class declaration I'm declaring rides like this:
var rides = [Ride]()
And above the error line I have added this:
let ride = self.rides[indexPath.row]
Screenshot:
And my Ride class:
Can someone tell me what I'm doing wrong and how to fix this?
struct Ride is not a subtype of NSDictionary. They are completely different concept.
Therefore, the casting if let rowData: NSDictionary = ride as? NSDictionary always fails.
Since rides's type is [Ride], let ride = rides[indexPath.row]'s type is Ride.
No optional unwrapping is required. Use the properties(name, state, ...) directly.
So, I think the code should be something like this.
let ride = rides[indexPath.row]
dataFull = ride.name
dataState = ride.state
dataUrlString = ride.image
...
just cast to the proper type : Ride
if let rowData = ride as? Ride,
but as the datasource is defined as Ride anyway this check is not needed at all
Edit:
The properties of Ride are all declared as non optional types, so you never have to check for nil. That's a huge benefit of the Swift language

Swift equivalent to `initWithContentsOfFile:`?

I am trying to use the Swift equivalent of initWithContentsOfFile: on an Array. The documentation states that the equivalent is convenience init(contentsOfFile aPath: String!)
I have tried to call this with the following code:
var path = NSBundle.mainBundle().pathForResource("Standards", ofType: "plist")
var rawStandards = Array<Dictionary<String, AnyObject?>>(contentsOfFile: path)
The compiler is telling me, however, that it couldn't find an overload that accepts the supplied arguments. What am I missing?
#Leo Natan was really close, but the way that worked for me was:
var rawStandards = NSArray(contentsOfFile: path)
I was then able to access the elements:
for obj: AnyObject in rawStandards {
if var rawStandard = obj as? NSDictionary {
}
}
You are initializing a Swift array, not an NSArray, which has the initWithContentsOfFile: initializer method.
Try:
var rawStandards = NSArray(contentsOfFile: path) as Dictionary<String, AnyObject?>[]
var path = NSBundle.mainBundle().pathForResource("Standards", ofType: "plist")
var menuItemArray = NSArray(contentsOfFile: path) as NSArray!
this is what i'm using myself. in viewDidLoad
Here is what worked for me. I've verified it in the beta build of Xcode. Unlike the other answers, I wanted a native typed Swift array with the results, so I took a few extra steps. (#wayne-hartman's answer may be more intuitive if you don't know what you have in your plist or don't want a typed Array.) It did require forcing types in a way I didn't expect.
My plist has dictionaries at the first level and strings at the second level, the code should be easy to adjust for other types.
let plistNSArray = NSBundle.mainBundle().pathForResource("myplist", ofType: "plist")
let untypedArray: AnyObject[] = plistNSArray
let typedArray = untypedArray as Dictionary<String,String>[] //Obviously you could do this conditionally for better error handling
for plistDictItem in typedArray {
for (dictKey,dictValue) in plistDictItem {
println("key \(dictKey) has value \(dictValue)")
}
}
It doesn't work (or at least I couldn't make it work) without the intermediate step of untypedArray.
#leo-natan's doesn't compile for me, even though it looks like it should to me. I believe that the compiler just can't automatically convert the NSArray into a typed Swift array directly without the intermediate step I added. It wouldn't surprise me if his code works in a future release.

Resources