I am trying to read the "value" field of a String in Kotlin. I am not very familiar with reflection in Kotlin, so I can't get it to work. This is what I have:
var str: String = "Some string"
val field = String::class.java.getDeclaredField("value")
field.isAccessible = true
println(field) // This prints "private final char[] java.lang.String.value"
println(field.get(str)) // This prints [C#66d3c617
When trying to cast char[] to Array, I get this exception:
java.lang.ClassCastException: [C cannot be cast to [Ljava.lang.Character;
What am I doing wrong?
I am not sure what you are trying to achieve but you can try this.
val value = (field.get(str) as ByteArray).toString(Charset.defaultCharset())
println(value)
In my env, the field is a ByteArray so I casted it to a ByteArray and get a printable version. In your case, a simple CharArray should suffice.
Related
How do i force unwrap an optional value thats "stored" as Any?
let optionalString: String? = "optional string"
let anyString: Any = optionalString
if let unwrappedString = anyString as? String {
println(unwrappedString)
// does not recognize the anyString as an optinal String
}
How do i write an if statement that force unwraps the value stored in anyString and prints the optionalString value? I have to do it only accessing the anyString attribute.
The use case for this is to get values out of MirrorType, which stores the attribute values as Any.
Ignore answer as not really providing a solution - the problem looks like a compiler bug
I'm not deleting it by now so readers know what I tried, and how I misunderstood the real question:
How to unwrap an optional value stored in a variable of Any type
Also be sure to read comments.
In your code you are using optional binding. Forced unwrapping instead uses the postfix ! operator:
println(optionalString!)
but if the optional string contains a nil value, that throws a runtime exception. So unless you are 100% sure it's not nil, I recommend using optional binding:
if let unwrappedString = optionalString {
println(unwrappedString)
}
That said, if you have an optional string stored in an Any variable, using optional downcasting and optional binding you can extract as follows:
var anyString: Any? = "optional string" as String?
if let unwrappedString = anyString as? String {
println(unwrappedString)
}
If you want to use a forced downcast, that's simply:
println(anyString as String)
but as in forced unwrapping, this causes a runtime exception if anyString is nil.
If the anyString variable is not optional, things are even simpler, because there's no optional binding, just optional downcasting, although the related code looks exactly the same:
var anyString: Any = "optional string"
if let downcastedString = anyString as? String {
println(downcastedString)
}
If you have an Any then you can test if it's optional and it it's nil by using something as:
var anyValue: String? = "The string"
var theValue: Any = anyValue
let mi:MirrorType = reflect(theValue)
if mi.disposition == .Optional {
if mi.count == 0 { return NSNull() } // Optional.None
let (name,some) = mi[0]
theValue = some.value
}
Now theValue will just be a String and not an Optional String. So you can cast it and use it as a String.
can anyone explain why line 1 works to create an empty swift dictionary but line 2 doesn't when i try to create a swift dictionary with int key and tuple of double values .... how should it be done?
var testDic2 = [Int:Double]()
var testDic3 = [Int:(Double,Double)]()
I've tried various combinations in playgrounds and the only version where it doesnt give me a compiler error is as follows
var possibleTips = [Int(): (tipAmt:Double(), total:Double())]
but im not sure this last form is declaring the dictionary as i intend it (ie as per testDict3 above)
The compiler isn't sure how to instantiate the type in your second and third example. Instead, you can declare the type and use an empty dictionary initializer:
var testDic:[Int:(Double,Double)] = [:]
I am trying to do this:
var dictArray = [String:[String]]()
dictArray["test"] = [String]()
dictArray["test"]! += "hello"
But I am getting the weird error NSString is not a subtype of 'DictionaryIndex<String, [(String)]>'.
I just want to be able to add objects to an array inside a dictionary.
Update: Looks like Apple considers this a "known issue" in Swift, implying it will work as expected eventually. From the Xcode 6 Beta 4 release notes:
...Similarly, you cannot modify the underlying value of a mutable
optional value, either conditionally or within a force-unwrap:
tableView.sortDescriptors! += NSSortDescriptor(key: "creditName", ascending: true)
Workaround: Test the optional value explicitly and then assign the
result back:
if let window = NSApplication.sharedApplication.mainWindow {
window.title = "Currently experiencing problems"
}
tableView.sortDescriptors = tableView.sortDescriptors!
You can only do this
var dictArray = [String:[String]]()
dictArray["test"] = [String]()
var arr = dictArray["test"]!;
arr += "hello"
dictArray["test"] = arr
because dictArray["test"] give you Optional<[String]> which is immutable
6> var test : [String]? = [String]()
test: [String]? = 0 values
7> test += "hello"
<REPL>:7:1: error: '[String]?' is not identical to 'UInt8'
append also won't work due to the same reason, Optional is immutable
3> dictArray["test"]!.append("hello")
<REPL>:3:18: error: '(String, [(String)])' does not have a member named 'append'
dictArray["test"]!.append("hello")
^ ~~~~~~
BTW the error message is horrible...
You may use NSMutableArray instead of [String] as a value type for your dictionary:
var dictArray: [String: NSMutableArray] = [:]
dictArray["test"] = NSMutableArray()
dictArray["test"]!.addObject("hello")
This is still an issue in Swift 3. At least I was able to create method that can handle it for you.
func appendOrCreate(newValue: Any, toArrayAt key: String, in existingDictionary: inout [AnyHashable:Any]) {
var mutableArray = [Any]()
if let array = existingDictionary[key] as? [Any]{
//include existing values in mutableArray before adding new value
for existingValue in array {
mutableArray.append(existingValue)
}
}
//append new value
mutableArray.append(newValue)
//save updated array in original dictionary
existingDictionary[key] = mutableArray
}
The problem is that we want class semantics here but have to use structs. If you put class objects into the dictionary, you get what you want!
So, if you haveĀ¹ to have mutable values, you can wrap them in a class and perform updates with a closure:
class MutableWrapper<T> {
var rawValue: T
init(_ val: T) {
self.rawValue = val
}
func update(_ with: (inout T) -> Void) {
with(&self.rawValue)
}
}
Example:
func foo() {
var dict = [String: MutableWrapper<[String]>]()
dict["bar"] = MutableWrapper(["rum"])
dict["bar"]?.update({$0.append("gin")})
print(dict["bar"]!.rawValue)
// > ["rum", "gin"]
}
For what it's worth, I do not see a way to keep caller and wrapper in sync. Even if we declare init(_ val: inout T) we will end up with a copy in rawValue.
Performance is not necessarily an issue since the compiler optimizes structs heavily. I'd benchmark any mutable solution against what looks like lots of copy-updates in the code.
Since Swift 4.1 you can provide a default value to the subscript which allows you to solve this quite naturally now:
dictArray["test", default: []].append("hello")
I'm trying to convert this objc code to swift:
CGContextRef contextRef = CGBitmapContextCreate(NULL,
proposedRect.size.width,
proposedRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
colorSpaceRef,
(CGBitmapInfo)kCGImageAlphaPremultipliedFirst);
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:contextRef flipped:NO];
So far I ended up with this:
var bitmapContext: CGContext = CGBitmapContextCreate(data, UInt(proposedRect.width), UInt(proposedRect.height), CGImageGetBitsPerComponent(image), 0, colorSpace, CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.toRaw()))
let context = NSGraphicsContext(graphicsPort: bitmapContext, flipped: false)
The problem is that CGBitmapContextCreate returns CGContext type and NSGraphicsContext initializer accepts graphicsPort as CMutableVoidPointer type. So how can I convert CGContext to CMutableVoidPointer?
related reverse type casting found here, but it didn't provide much help to me
How to convert COpaquePointer in swift to some type (CGContext? in particular)
I ended up with the reinterpretCast function returning intermediate Int variable for the bitmapContext address.
var bitmapContext: CGContext = CGBitmapContextCreate(...)
let bitmapContextAddress: Int = reinterpretCast(bitmapContext)
let bitmapContextPointer: CMutableVoidPointer = COpaquePointer(UnsafePointer<CGContext>(bitmapContextAddress))
let context = NSGraphicsContext(graphicsPort: bitmapContextPointer, flipped: false)
The documentation here:https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/InteractingWithCAPIs.html
states the following:
When a function is declared as taking a CMutableVoidPointer argument,
it can accept the same operands as CMutablePointer for any type
Type.
From that, it should work like this:
var p: CMutablePointer<CGContext> = &bitmapContext
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:p flipped:NO];
Extended practically, you should be able to pass in &bitmapContext directly to a CMutableVoidPointer argument.
Swift doesn't have "pointers" in the C sense.
So I started a project in Swift, and I've come to this problem:
this code works:
var dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
println(dictionary)
dictionary["c"] = "newValOfC"
println(dictionary)
and this doesn't:
var dictionary = [:]
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
println(dictionary)
dictionary["c"] = "newValOfC"
println(dictionary)
Gives an error:
Playground execution failed: error: <REPL>:35:17: error: cannot assign to the result of this expression
dictionary["c"] = "newValC"
~~~~~~~~~~~~~~~ ^
Notice that this is not a constant value
So why doesn't the line
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
give an error?
Since the context does not provide enough information to infer the type, you'll need to explicitly name it as a dictionary, otherwise swift assumes it is an NSDictionary (I'm not clear on why though. I assume for better obj-c compatibility):
The following code all works:
// Playground
import UIKit
var str:NSString = "Hello, playground"
var d0 = [:]
var d1: Dictionary = [:]
d0.setValue(UIWebView(), forKey: "asdf")
d1["asdf"] = 1
d1["qwer"] = "qwer"
Okay, I found it, the problem is that by initializing an empty dictionary, the type inference gets a little crazy.
You'll need this code:
var dictionary = Dictionary<String, String>()
instead of
var dictionary = [:]
but that still does not explain why the line
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
does not give an error
And referring to Swift Language Guide, the
dictionary = [:]
syntax is correct "if the context already provides type information".
The big difference is that
var dictionary = [:]
doesn't give any chance the compiler to infer the right type, whereas
var dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
does.
Actually it looks like the first line produces a __NSDictionaryI instance, whereas the second one produces a Dictionary<String,String as expected.
From The Swift Programming Language book
If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [:] (a colon inside a pair of square brackets):
which means the first line is ambiguous.
The [:] syntax only works if the current context has enough information to be able to infer what the types are. Here are a few ways where the context is known...
As has been mentioned already, the code below works because it can be inferred that the keys and values are strings:
var dictionary = [ "a" : "valueOfA" , "b" : "valueOfB" , "c" : "valueOfC" ]
A dictionary passed into a function has a known context:
func dictionaryFunc(var dictionary : Dictionary<String, String>) {
// Do stuff with the dictionary
}
In both cases, the key/value types for the dictionary are now known, so you could do this to create a new dictionary with the same variable name...
dictionary = [:]
In the first case, if you used the [:] syntax after the declaration you would be erasing the contents of the original dictionary. In the second case, dictionaries get copied when they get passed into functions, so using [:] would only be erasing the copy.
In Swift 2.0 I'm using this:
var dictionary = [String:String]()
dictionary["key1"] = "value1"