I have a userInfo dictionary from a UILocalNotification. Is there an easy way to get the String value when using implicit unwrapping?
if let s = userInfo?["ID"]
Gives me a AnyObject that I have to cast to a string.
if let s = userInfo?["ID"] as String
Gives me an error about StringLiteralConvertable
Just didn't want to have to declare two variables to get a string - one literal for the unwrap and another var for the casted string.
Edit
Here is my method. This doesn't work either - I get (NSObject, AnyObject) is not convertible to String on the if statement.
for notification in scheduledNotifications
{
// optional chainging
let userInfo = notification.userInfo
if let id = userInfo?[ "ID" ] as? String
{
println( "Id found: " + id )
}
else
{
println( "ID not found" )
}
}
I don't have it in my question, but besides getting this way to work, I'd like to actually have
if let s = notification.userInfo?["ID"] as String
You want to use a condition cast using as?:
(Note: This works for Xcode 6.1. For Xcode 6.0, see below)
if let s = userInfo?["ID"] as? String {
// When we get here, we know "ID" is a valid key
// and that the value is a String.
}
This construct safely extracts a string from userInfo:
If userInfo is nil, userInfo?["ID"] returns nil due to optional chaining and the conditional cast returns a variable of type String? that has a value of nil. The optional binding then fails and the block is not entered.
If "ID" is not a valid key in the dictionary, userInfo?["ID"] returns nil and it proceeds like the previous case.
If the value is another type (like Int), then the conditional cast as? will return nil and it proceeds like the above cases.
Finally, if userInfo is not nil, and "ID" is a valid key in the dictionary, and the type of the value is a String, then the conditional cast returns an optional string String? containing the string. The optional binding if let then unwraps the String and assigns it to s which will have type String.
For Xcode 6.0, there is one additional thing you must do. You need to conditionally cast to NSString instead of to String because NSString is an object type and String is not. They apparently improved that handling in Xcode 6.1, but for Xcode 6.0 do the following:
if let s:String = userInfo?["ID"] as? NSString {
// When we get here, we know "ID" is a valid key
// and that the value is a String.
}
Finally, addressing your last point:
for notification in scheduledNotifications
{
if let id:String = notification.userInfo?["ID"] as? NSString
{
println( "Id found: " + id )
}
else
{
println( "ID not found" )
}
}
Related
Player Object Model
In the Player Model, I want to save the JSON response so that I will get any new computed properties in the future without changing the schema.
But here, I'm getting the error to save the json of type [String: Any].
Any alternative or recommendations...?
Any is not a supported value type of Map. Looking a the documentation for Map, which shows the definition
public final class Map<Key, Value>
value is a RealmCollectionValue can be one of the following types
This can be either an Object subclass or one of the following types:
Bool, Int, Int8, Int16, Int32, Int64, Float, Double, String, Data,
Date, Decimal128, and ObjectId (and their optional versions)
One option is to to use AnyRealmValue so it would look like this
class Player: Object {
let json = Map<String, AnyRealmValue>()
}
here's how to populate the json with a string and an int
let s: AnyRealmValue = .string("Hello")
let i: AnyRealmValue = .int(100)
let p = Player()
p.json["key 0"] = s
p.json["key 1"] = i
then to get back the values stored in the map:
for key in p.json {
let v = key.value
if let s = v.stringValue {
print("it's a string: \(s)")
} else if let i = v.intValue {
print("it's an int: \(i)")
}
}
and the output
it's a string: Hello
it's an int: 100
Live example here.
type Activity = {
verb: string
}
type CommentActivity = {
verb: 'comment'
}
function doStuff (activity: Activity) {}
const commentActivity: CommentActivity = { verb: 'comment' }
const likeActivity: Activity = { verb: 'like' }
doStuff(likeActivity)
doStuff(commentActivity)
Fails with:
15: doStuff(commentActivity)
^ Cannot call `doStuff` with `commentActivity` bound to `activity` because string literal `comment` [1] is incompatible with string [2] in property `verb`.
References:
6: verb: 'comment' ^ [1]
2: verb: string ^ [2]
The error message is clear and I know how to work around this, but I don't understand why a string literal isn't considered a valid string?
This is an issue of property variance. If you have a function like doStuff with the type
(activity: Activity): void => {}
then it is perfectly valid for the function do to
function doStuff (activity: Activity) {
activity.verb = "some new verb";
}
and that 100% typechecks. What that means is that if
doStuff(commentActivity)
were allowed, doStuff would actually change the type of commentActivity, which is why this is throwing an error for you.
What you need to do is tell Flow that you will not be changing the value of .verb, essentially making it read-only inside of doStuff. To do this, you put a + before the name of the property.
type Activity = {
+verb: string
};
(On Flow/try)
I have code that sends a notification (where serialNumber is a String):
var dataDict = Dictionary<String, String>()
dataDict["Identity"] = serialNumber
dataDict["Direction"] = "Add"
NSNotificationCenter.defaultCenter().postNotificationName("deviceActivity", object:self, userInfo:dataDict)
And code that receives this notification:
func deviceActivity(notification: NSNotification) {
// This method is invoked when the notification is sent
// The problem is in how to access the Dictionary and pull out the entries
}
I've tried a variety of code to accomplish this, with no success:
let dict = notification.userInfo
let dict: Dictionary<String, String> = notification.userInfo
let dict: Dictionary = notification.userInfo as Dictionary
And while some of my attempts satisfy the compiler, none have yielded actual Strings when trying to access what has been extracted as a Dictionary:
let sn : String = dict["Identity"]!
let sn : String = dict.valueForKey("Identity") as String
let sn : String = dict.valueForKey("Identity")
So the question is this: How do I write Swift code to extract an object, in this case a Dictionary, that was passed via a notification, and access the component parts of that object (in this case the keys and values)?
As notification.userInfo type is AnyObject ayou must downcast it to appropriate dictionary type.
After exact type of dictionary is known you don't need to downcast values you get from it. But you may want to check if values are actually present in dictionary before using them:
// First try to cast user info to expected type
if let info = notification.userInfo as? Dictionary<String,String> {
// Check if value present before using it
if let s = info["Direction"] {
print(s)
}
else {
print("no value for key\n")
}
}
else {
print("wrong userInfo type")
}
You should use structure like [NSObject : AnyObject] and retrieve value as from NSDictionary yourLet[key]
func keyboardWillShown(notification : NSNotification){
let tmp : [NSObject : AnyObject] = notification.userInfo!
let duration : NSNumber = tmp[UIKeyboardAnimationDurationUserInfoKey] as NSNumber
let scalarDuration : Double = duration.doubleValue
}
when I call select in other function, there is problem in line number 3.
Is it wrong?
public String[] select(int n){
db = helper.getReadableDatabase();
Cursor c = db.rawQuery("SELECT * FROM info WHERE number='" + n + "'", null);
}
The rawQuery() looks good, though usually you wouldn't quote integers as 'string literal'.
However, a non-void method must return a value and your method doesn't return anything. Add return null; to make it compile; implement a loop that builds a string array to return a non-null value.
How do I parse query strings safely in Dart?
Let's assume I have q string with the value of:
?page=main&action=front&sid=h985jg9034gj498g859gh495
Ideally the code should work both in the server and client, but for now I'll settle for a working client-side code.
The simpler, the better. Look for the splitQueryString static method of class Uri.
Map<String, String> splitQueryString(String query, {Encoding encoding: UTF8})
Returns the query split into a map according to the rules specified for
FORM post in the HTML 4.01 specification section 17.13.4. Each key and value
in the returned map has been decoded. If the query is the empty string an
empty map is returned.
I have made a simple package for that purpose exactly: https://github.com/kaisellgren/QueryString
Example:
import 'package:query_string/query_string.dart');
void main() {
var q = '?page=main&action=front&sid=h985jg9034gj498g859gh495&enc=+Hello%20&empty';
var r = QueryString.parse(q);
print(r['page']); // "main"
print(r['asdasd']); // null
}
The result is a Map. Accessing parameters is just a simple r['action'] and accessing a non-existant query parameter is null.
Now, to install, add to your pubspec.yaml as a dependency:
dependencies:
query_string: any
And run pub install.
The library also handles decoding of things like %20 and +, and works even for empty parameters.
It does not support "array style parameters", because they are not part of the RFC 3986 specification.
I done that just like this:
Map<String, String> splitQueryString(String query) {
return query.split("&").fold({}, (map, element) {
int index = element.indexOf("=");
if (index == -1) {
if (element != "") {
map[element] = "";
}
} else if (index != 0) {
var key = element.substring(0, index);
var value = element.substring(index + 1);
map[key] = value;
}
return map;
});
}
I took it from splitQueryString