Can't cast to NSMutableString in Swift - 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.

Related

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.

EXC Bad Instruction

In was wondering why I keep getting this error message, EXC Bad Instruction could someone help me out and tell me why.
Here is the code.
func updateStocks() {
let stockManager:StockManagerSingleton = StockManagerSingleton.sharedInstance
stockManager.updateListOfSymbols(stocks)
//Repeat this method after 15 secs. (For simplicity of the tutorial we are not cancelling it never)
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(15 * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(),
{
self.updateStocks()
}
)
}
//4
func stocksUpdated(notification: NSNotification) {
let values = (notification.userInfo as! Dictionary<String,NSArray>)
let stocksReceived:NSArray = values[kNotificationStocksUpdated]!
stocks.removeAll(keepCapacity: false)
for quote in stocksReceived {
let quoteDict:NSDictionary = quote as! NSDictionary
let changeInPercentString = quoteDict["ChangeInPercent"] as! String
let changeInPercentStringClean: NSString = (changeInPercentString as NSString).substringToIndex((changeInPercentString as NSString).length-1)
stocks.append(quoteDict["symbol"] as! String,changeInPercentStringClean.doubleValue)
}
tableView.reloadData()
NSLog("Symbols Values updated :)")
}
}
The line with the error in it is,
let changeInPercentString = quoteDict["ChangeInPercent"] as! String
The error states that Swift attempted to unwrap a nil value, as you stated on this line
let changeInPercentString = quoteDict["ChangeInPercent"] as! String
Swift attempts to force setting the value of quoteDict["ChangeInPercent"] to a String, because you use as!, instead, you should use as?, which will set the value to nil if the value cannot be found
let changeInPercentString = quoteDict["ChangeInPercent"] as? String
You could set this to a default value by using the ?? operator. For example, if you wanted the default value to be 0.0%, you could use
let changeInPercentString = (quoteDict["ChangeInPercent"] as? String) ?? "0.0%"
The inherent problem is most likely either that quoteDict["ChangeInPercent"] does not exist, or quoteDict["ChangeInPercent"] is not a String - it may be an NSString or simply a Double value.
If you find out that it is supposed to be an NSString, for example, you will need to change how you cast the value
let changeInPercentString: NSString = (quoteDict["ChangeInPercent"] as? NSString) ?? "0.0%"

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 'count' compiler error

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
}
}

Get NSImage from NSTextField in Swift

I used to retrieve the NSImage in a subclass of NSTextField from Obj-C like this:
NSDictionary *attributedVal = [[self attributedStringValue] attributesAtIndex:i effectiveRange:&effectiveRange];
if ([[attributedVal allKeys] containsObject:NSAttachmentAttributeName]) {
NSTextAttachment *attachment = [attributedVal valueForKey:NSAttachmentAttributeName];
NSCell *attachmentCell = (NSCell *)[attachment attachmentCell];
... [[attachmentCell image] name] ...
}
When I try to do the same in Swift I can't seem to be able to cast attachmentCell but get a compiler error:
let attributedVal = attributedStringValue.attributesAtIndex(i, effectiveRange: effectiveRange)
if let attachment = attributedVal[NSAttachmentAttributeName] as? NSTextAttachment {
let attachmentCell = attachment.attachmentCell as NSCell // does not work
...
}
Thanks to Nate Cook. The following works:
let attributedVal = attributedStringValue.attributesAtIndex(i, effectiveRange: effectiveRange)
if let attachment = attributedVal[NSAttachmentAttributeName] as? NSTextAttachment {
let attachmentCell = attachment.attachmentCell as NSTextAttachmentCell
let image = attachmentCell.image
...
}