In converting an app from Objective C to Swift 3, many of the data structures are no longer classes, but structs. In a particular function, I need to use the NSKeyedArchiver.archivedData(withRootObject: function to encapsulate these structs before sending them over a network connection, so I've converted them to good old Objective-C objects. But the code below still crashes when I attempt to encode them.
enum CustomDataType:Int
{
case CustomDataType0 = 0
case CustomDataType1 = 1
case CustomDataType2 = 2
case CustomDataType3 = 3
case CustomDataType4 = 4
}
func send(dataType:CustomDataType, dictionary: Dictionary<String, Any>)
{
// convert everything into objects
let dataTypeObject:NSNumber = NSNumber(integerLiteral: dataType.rawValue)
let dataValueObject:NSDictionary = dictionary as NSDictionary
let dataTypeObjectKey:NSString = "regis-type"
let dataValueObjectKey:NSString = "regis-value"
let transmissionData:NSDictionary = [dataTypeObjectKey : dataTypeObject, dataValueObjectKey :dataValueObject]
let data = NSKeyedArchiver.archivedData(withRootObject: transmissionData)
The last line produces a crash, and I'm baffled. Any thoughts?
Crash log:
[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x170448df0
2017-02-22 17:10:10.338319 cd Swift[441:56841] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x170448df0'
Related
I want to convert userInfo data from a NSNotification to an enum to use in a switch statement. The notification is coming from a pre-compiled c++ framework with some headerfiles defining te enum.
-(void)updateOTAStatus:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
otaUpgradeStatus status = (otaUpgradeStatus)userInfo[#"status"];
//...
}
Enum definition:
typedef NS_ENUM(NSUInteger, otaUpgradeStatus) {
none = 0,
started = 1,
inProgress = 2,
completed = 3,
failed = 4,
failedLowBattery = 5,
cancelled = 6,
timedout = 7,
forced = 8
};
When debugging I get
Printing description of status:
(otaUpgradeStatus) status = 6178538944
And switch statement fails, when I do the same in Swift:
let status = notification.userInfo?["status"] as? otaUpgradeStatus
I get the right status back, and switch statement works as expected.
What goes wrong here?
An NSDictionary can only hold objects, i.e. instances of (a subclass of) NSObject. Swift has a mechanism to wrap/unwrap values in an
opaque _SwiftValue instance transparently.
But for interoperability with Objective-C you have to put the number
as NSNumber instances into the user info dictionary on the Swift side, e.g.
let notification = Notification(name: ..., object: ...,
userInfo: ["status": NSNumber(value: otaUpgradeStatus.failed.rawValue)])
and extract the integer value on the Objective-C side, e.g.
NSDictionary *userInfo = notification.userInfo;
NSNumber *num = userInfo[#"status"];
otaUpgradeStatus status = num.unsignedIntegerValue;
I'm trying to save data in an image metadata in iOS/Swift3. It does not appear that CG will let you save out custom tags (is that true?) so I JSON encoded my dictionary and put the result as a string into the TIFF tag's ImageDescription. When I load the image and get the metadata back...
if let data = NSData(contentsOfFile:oneURL.path), let imgSrc = CGImageSourceCreateWithData(data, options as CFDictionary) {
let allmeta = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options as CFDictionary) as? [String : AnyObject]
The allMeta contains (among other things):
▿ 0 : 2 elements
- key : ImageDescription
- value : {
"CameraOrientationW" : 0.1061191,
"CameraOrientationZ" : -0.01305595,
"CameraOrientationX" : 0.01319851,
"CameraOrientationY" : 0.9941801
}
Which has the JSON data, yay! So now I simply have to get the TIFF metadata, get the ImageDescription from that, and de-JSON it...
let tiffmeta = allmeta?["{TIFF}"]
if let tiffMeta = tiffmeta {
let descmeta = tiffMeta["ImageDescription"]
var descdata = descmeta?.data(usingEncoding: NSUTF8StringEncoding)!
let descdict = try? JSONSerialization.jsonObject(with: descdata, options: [])
But this will not compile. Xcode puts an error on the let descdata line:
Value of type 'MDLMaterialProperty??' has no member 'data'
I tried casting it to String on the line above, at which point it complains I didn't unwrap the optional MDLMaterialProperty.
Am I missing something obvious here?
So just to close this one, this appears to be a problem in the compiler. I made a number of minor changes to the syntax, nothing that had any actual effect on the code, and suddenly it decided the object was indeed a string.
I am reading my data through a web service that returns a percentage as a string and I need to format it properly in my app. Currently I receive an error message that reads "Argument labels '(_:)' do not match any available overloads".
Suggestions on how to resolve this issue?
if let dUnInsured = result[0]["UnInsured"] as? String, let doubleNum = Double(dUnInsured) {
let sUnInsured = dollarFormatter.string(from: (NSDecimalNumber(Decimal(doubleNum))))!
self.inUninsured.text = sUnInsured
}
Try like this way.
if let dUnInsured = result[0]["UnInsured"] as? String, let doubleNum = Double(dUnInsured) {
let sUnInsured = dollarFormatter.string(from: (NSNumber(value: doubleNum)))!
self.inUninsured.text = sUnInsured
}
I'm trying to use Google Visualizations from Scala.js. I generated the type definitions using TS importer and the relevant portion it generated is:
#js.native
trait ColumnChartOptions extends js.Object {
var aggregationTarget: String = js.native
var animation: TransitionAnimation = js.native
var annotations: ChartAnnotations = js.native
// ... more
}
#js.native
trait TransitionAnimation extends js.Object {
var duration: Double = js.native
var easing: String = js.native
var startup: Boolean = js.native
}
Now, I'm trying to figure out how to actually use this and came up with:
val options = js.Dynamic.literal.asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal.asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
options.animation.duration = 2000
options.title = "Test Chart"
options.width = 400
options.height = 300
This works if I don't set the animation settings, but fails with the chart showing "Maximum call stack size exceeded" if I do.
I debugged, and found the following:
So animation contains a reference to itself, but I don't feel like this should happen based on the code above.
Ideas how to fix it?
Any other suggestions on how to best use the generated types to provide a type-safe way of creating the JavaScript objects which Google Visualizations expects? I tried new ColumnChartOptions {} which looks cleaner than js.Dynamic but that failed with "A Scala.js-defined JS class cannot directly extend a native JS trait."
P.S. I'd like to note that
options.animation = js.Dynamic.literal(
easing = "inAndOut",
startup = true,
duration = 2000
).asInstanceOf[TransitionAnimation]
actually works, but isn't type-safe (a mis-spelling of duration to durration won't be caught).
Your code lacks () when calling literal(), so the fix would be:
val options = js.Dynamic.literal().asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal().asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
In Scala (and therefore in Scala.js), the presence or absence of () is sometimes meaningful. literal is the singleton object literal, whereas literal() calls the method apply() of said object.
So my code below shows me how I am doing prepare for segue. I'm not sure whats going on but its giving me some weird error I've used this same way before and it works but it just won't work in this application.
Code
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
{
if segue.identifier == "select"
{
println("helloworld")
var index = tableView.indexPathForCell(sender as UITableViewCell!)
var object = self.objects[index!.row] as HMAccessory // object is a NSmutableArray its crashing on this next line where im casting it
//var dest = segue!.destinationViewController? as CharacristicsViewController!
// dest.detailItem = object
}
}
can anybody see anything wrong with this?
This is the error I'm getting.
HomeKit`HomeKit.AccessoryTableViewController.prepareForSegue
(HomeKit.AccessoryTableViewController)(Swift.ImplicitlyUnwrappedOptional,
sender : Swift.ImplicitlyUnwrappedOptional) -> () at
AccessoryTableViewController.swift:23: