'AnyObject?' does not have a member named 'count' compiler error - swift

First of all, I tried using JSON Serialization in the following code and I tried looping through each items available in the array. However, it must be type casting that I am missing something. Here is the snippet of what I am trying to do:
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:
NSJSONReadingOptions.MutableContainers, error: nil) as
NSDictionary
var items = [[String:String]()]
var item: AnyObject
var authorDictionary: AnyObject
for var i = 0; i < jsonResult["items"].count; i++ {
items.append([String:String]())
items[i]["content"] = item["content"] as? NSString
items[i]["title"] = item["title"] as? NSString
items[i]["publishedDate"] = item["published"] as? NSString
authorDictionary = item["author"] as NSDictionary
items[i]["author"] = item["displayName"] as? NSString
}

To resolve your error, change this:
jsonResult["items"]
to this:
(jsonResult["items"] as! NSArray)

Sorry, i am not with my xcode here, but looking the code i think in something about this.
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:
NSJSONReadingOptions.MutableContainers, error: nil) as
NSDictionary
var items = [[String:String]()]
var item: AnyObject
var authorDictionary: AnyObject
if let itemsFromJson:NSArray = jsonResult["items"] as? NSArray
{
for itemJson in itemsFromJson {
items.append([String:String]())
items[i]["content"] = itemJson["content"] as? NSString
items[i]["title"] = itemJson["title"] as? NSString
items[i]["publishedDate"] = itemJson["published"] as? NSString
authorDictionary = itemJson["author"] as NSDictionary
items[i]["author"] = itemJson["displayName"] as? NSString
}
}

Related

Can't cast to NSMutableString in Swift

I have Swift struct like this:
if(isSearching == true){
let contactDict :NSDictionary = self.filteredArray?.object(at: indexPath.row) as! NSDictionary;
let strArray :NSArray = contactDict.object(forKey: kName) as! NSArray
nameString = strArray.componentsJoined(by: "") as! NSMutableString
//nameString = (contactDict.object(forKey: kName) as? String as! NSMutableString)
companyNameString = (contactDict.object(forKey: kCompanyName) as AnyObject).object(at: 0) as? NSString;
designationString = (contactDict.object(forKey: kDesignation) as AnyObject).object(at: 0) as? NSString;
profileImage = contactDict.object(forKey: kProfilePic) as? UIImage;
connectStatus = contactDict.value(forKey: kLinkStatus) as? NSString;
if(profileImage?.accessibilityIdentifier == "Img_placeholder"){
profileImage = nil;
}
The error showing like this :
Could not cast value of type 'NSTaggedPointerString' (0x1b5b89900) to 'NSMutableString' (0x1b5b959c0)
How can i solve this issue?
If you need nameString to be a NSMutableString, then try this:
nameString: NSMutableString = strArray.componentsJoined(by:"").mutableCopy()
The error comes from
nameString = strArray.componentsJoined(by: "") as! NSMutableString
because you can't downcast here. NSTaggedPointerString is a (private) subclass of NSString but not of NSMutableString. You should create a new mutable string instead:
nameString = NSMutableString(string: strArray.componentsJoined(by: ""))
But as #Sweeper said in the comments it should be better to use Swift strings.

Switch from NSDictionary to Dictionary

I have some code to get EXIF data from file, but it uses NS-Types. I like to get Swift 3 conform and use standard swift types like Dictionary or String. When deleting "NS", I get the error that ".value()" does not exist. And no hint by the compiler what is the new function call:
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as NSDictionary
let exifDict = imageProperties.value(forKey: "{Exif}") as! NSDictionary
let dateTimeOriginal = exifDict.value(forKey: "DateTimeOriginal") as! NSString
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict.value(forKey: "PixelXDimension") as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties.value(forKey: "{TIFF}") as! NSDictionary
// optional
if let Software = exifDictTIFF.value(forKey: "Software") as? NSString {
print ("Software: \(Software)")
}
Any hint how to change it?
Additionally:
Using this
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as Dictionary
let exifDict = imageProperties["{Exif}"] as! Dictionary
will deliver an error "Ambiguous reference to member 'subScript'" for the second row!
All of the NSDictionary needs to be something like [String:Any]. And all of the value calls should use normal key access.
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil) as! [String:Any]
let exifDict = imageProperties["{Exif}"] as! [String:Any]
let dateTimeOriginal = exifDict["DateTimeOriginal"] as! String
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict["PixelXDimension"] as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties["{TIFF}"] as! [String:Any]
// optional
if let Software = exifDictTIFF["Software"] as? String {
print ("Software: \(Software)")
}
This code is terrible. All of those uses of ! are a bad idea. Proper, safe unwrapping and casting should be used throughout this code.

Swift: Unable to get array values from singleton class

Hi I retrived value from JSON and stored in NSMutableArray. I have tried this like Singleton. I have used empty swift file for this. Datas successfully retrieved and stored in NSMutableArray which is already declared in mainViewController. Then, if I use that NSMutableArray value in mainViewController, it shows empty array.
My coding is below. Kindly guide me.
Empty Swift File
public class json_file{
var prod_Obj = product_mainVC()
class var shared: json_file
{
struct Static
{
static let instance: json_file = json_file()
}
return Static.instance
}
func dataFromJSON()
{
let url = NSURL(string: "http://........--...4900a20659")!
var data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)!
var dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
let dataArray = dict["data"] as [[String:AnyObject]] // The array of dictionaries
for object in dataArray {
let category_name = object["category_name"] as String
prod_Obj.ct_name_arr.addObject(category_name)
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_name = child["sub_category_name"] as String
prod_Obj.sub_ct_name_arr.addObject(sub_category_name)
}
}
println(prod_Obj.ct_name_arr) //Here value is Getting
println(prod_Obj.sub_ct_name_arr) //Here value is Getting
}
}
viewDidLoad
{
json_file.shared.dataFromJSON()
println(ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
println(sub_ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
}
I was trying understand the problem, but I can't see the product_mainVC. Because this I remake your class with little modifications.
class JsonFile
{
private(set) var categoryNames:[String];
private(set) var subCategoryNames:[String];
class let shared:JsonFile = JsonFile();
private init()
{
self.categoryNames = [];
self.subCategoryNames = [];
}
func dataFromJson()
{
let url = NSURL(string: "http://........--...4900a20659")!
if let data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)
{
if let dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary
{
if let dataArray = dict["data"] as? [[String:AnyObject]] // The array of dictionaries
{
for object in dataArray {
let category_id = object["category_id"] as Int
let category_name = object["category_name"] as String
categoryNames.append(category_name);
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_id = child["sub_category_id"] as Int
let sub_category_name = child["sub_category_name"] as String
subCategoryNames.append(sub_category_name);
}
}
}
}
}
println(categoryNames);
println(subCategoryNames);
}
}
I did
Modify your way to do Singleton to a safe and more simple mode, create the arrays categoryNames and subCategoryNames internal in class because this is better to manipulate, and protect your fetch data to safe from possibles crash.
Implementation
JsonFile.shared.dataFromJson();
println("count categoryNames");
println(JsonFile.shared.categoryNames.count);
println("count subCategoryNames");
println(JsonFile.shared.subCategoryNames.count);
You need think about
This code is sync, and because this if you have a big data or request slow, the main thread from your application will freeze waiting return and it is bad for your user. Think if is necessary be sync.
let category_id = object["category_id"] as Int is never used. Why do you stay with this in code?

Swift - Why can I not return an NSNumber or Double data type from this NSDictionary object?

The second line of the code segment below returns an error unless I change the portion that reads "as NSNumber" to "as String". The value returned in rowData["lngID"] is a numeric value. Can someone please explain this to me?
let rowData: NSDictionary = objReport as NSDictionary
let lngReportID = rowData["lngID"] as NSNumber
What I'm actually attempting to do here is take a JSON response and load it into an array of objects as follows. Perhaps there is a better way to achieve this. Any suggestions for a better approach is much appreciated. First, the function didReceiveAPIResults returns the results to the app. Then the function loadReportsIntoArray is called.
func loadReportsIntoArray(pReports: NSArray) {
arrayPoints = []
for (intRow, objReport) in enumerate(pReports) {
// index is the index within the array
// participant is the real object contained in the array
let rowData: NSDictionary = objReport as NSDictionary
let lngReportID = rowData["lngID"] as NSNumber
let lngReportTypeID = rowData["lngTypeID"] as NSNumber
let strOtherTypeName = rowData["strOtherTypeName"] as String
let strDescription = rowData["strDescription"] as String
let dtmFirstReport = rowData["dtmFirstReport"] as String
let dblLat = rowData["dblLat"] as NSNumber
let dblLong = rowData["dblLong"] as NSNumber
let strReportedByUsername = rowData["strReportedByUsername"] as String
let lngReportedByID = rowData["lngReportedBy"] as NSNumber
let lngCommentCount = rowData["lngCommentCount"] as NSNumber
let lngNumLikes = rowData["lngNumLikes"] as NSNumber
let blnUserLikedEvent = rowData["blnUserLikedEvent"] as Bool
var objReport = Report(plngReportID: lngReportID, plngReportTypeID: lngReportTypeID, pstrOtherTypeName: strOtherTypeName, pstrDescription: strDescription, pdtmFirstReport: dtmFirstReport, pdblLat: dblLat, pdblLong: dblLong, pstrReportedByUsername: strReportedByUsername, plngReportedByID: lngReportedByID, plngCommentCount: lngCommentCount, plngNumLikes: lngNumLikes, pblnUserLikedEvent: blnUserLikedEvent)
//arrayPoints.append(objReport)
}
}
func didReceiveAPIResults(results: NSDictionary) {
var success: NSInteger = results["success"] as NSInteger
if success == 1 {
var resultsArr = results["geopoints"] as NSArray
dispatch_async(dispatch_get_main_queue(), {
self.loadReportsIntoArray(resultsArr)
})
}
else {
// Error occurred
}
}
I was able to recreate your error using the following code:
let objReport = NSDictionary(object: "string", forKey: "lngID")
let rowData: NSDictionary = objReport as NSDictionary
let lngReportID = rowData["lngID"] as NSNumber // Error
However, changing the objReport to NSDictionary(object: NSNumber(integer: 0), forKey: "lngID") solved the problem. Therefore, I think your problem is the object stored for the key lngID isn't an NSNumber.
For the solution to this you should look at Kumar Nitin's answer to check you've got a number stored, or you could use the code, they both do the same thing pretty much:
if let lngID = rowData["lngID"] as? NSNumber {
// Do stuff with lngID.
}
In swift, you don't have NSNumber, however you can use the Obj C's NSNumber if need be.
The above code for NSNumber should be as follows if you are expecting a double or float or int. Add a check to ensure the value is not nil, or else it will crash your app.
if let lngReportID = rowData["lngID"] as? Int {
//Do the task required
}

AnyObject? does not have a member named 'objectAtIndex'

Got a error on (Xcode6 BETA 6) if a try to get an object of string:
let jsonString : String = "[{\"name\":[\"Fred\",\"John\"],\"age\":21},{\"name\":\"Bob\",\"age\":35}]"
let myData:NSData? = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var jsonResult:NSArray = NSJSONSerialization.JSONObjectWithData(myData!, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSArray
println(jsonResult.objectAtIndex(0).objectForKey("name").objectAtIndex(0))
print never get called, cause the error. Anyone a idea?
Getting value from NSDictionary or NSArray return AnyObject object. So you should type cast to appropriate type. Try this
println(((jsonResult.objectAtIndex(0) as NSDictionary).objectForKey("name") as NSArray).objectAtIndex(0))
Another option would be to cast jsonResult to an Array<AnyObject> and use subscript syntax to get necessary value
let jsonString : String = "[{\"name\":[\"Fred\",\"John\"],\"age\":21},{\"name\":\"Bob\",\"age\":35}]"
let myData:NSData? = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var jsonResult: AnyObject = NSJSONSerialization.JSONObjectWithData(myData!, options: NSJSONReadingOptions.MutableContainers, error: nil);
if let lJsonArray = jsonResult as? Array<AnyObject> {
println(lJsonArray[0].objectForKey("name")[0])
}
I would suggest creating one or more classes and deserializing that JSON, to better access to the data and avoiding mistakes when accessing.
By the way by making data types more explicit it works:
let dict = jsonResult.objectAtIndex(0) as NSDictionary
let array = dict["name"] as NSArray
println(array.objectAtIndex(0))