extension of Dictionary where String, AnyObject
>=3.1
From 3.1, we can do concrete extensions, ie:
extension Dictionary where Key == String {}
<3.1
We can not conform concrete types w/ concrete generics, ie:
extension Dictionary where Key == String
However, because Dictionary conforms to sequence and we can conform protocol types w/ concrete generics, we could do:
extension Sequence where Iterator.Element == (key: String, value: AnyObject) {
func doStuff() {...
Otherwise, we can constrain our key to a protocol that string conforms to like this:
extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
var jsonString: String {
return ""
}
}
As per your updated answer. Json serialization needs an object, Swift Dictionaries are structs. You need to convert to an NSDictionary
You must specify Key
to conform to NSObject
to properly convert to an NSDictionary
.
Small note: Dictionaries already type constrain
Key
to beHashable
, so your original constraint wasn't adding anything.
extension Dictionary where Key: NSObject, Value:AnyObject {
var jsonString:String {
do {
let stringData = try NSJSONSerialization.dataWithJSONObject(self as NSDictionary, options: NSJSONWritingOptions.PrettyPrinted)
if let string = String(data: stringData, encoding: NSUTF8StringEncoding){
return string
}
}catch _ {
}
return ""
}
}
Note, that the dictionaries must conform to this type to access the extension.
let dict = ["k" : "v"]
Will become type [String : String]
, so you must be explicit in declaring:
let dict: [NSObject : AnyObject] = ["k" : "v"]
Extending Optional Dictionary String, AnyObject
use dot syntax to access the Key and Value of Wrapped.
extension Optional where Wrapped: DictionaryLiteralConvertible, Wrapped.Key: StringLiteralConvertible, Wrapped.Value: AnyObject {
func doSomething() {
print("did it")
}
}
now you can call this:Optional(["asdf":123]).doSomething()
but not this:Optional([123:123]).doSomething()
How to write Dictionary extension that handles optional values
You could do this with reflection. Doesn't require much more code than you already have:
extension Dictionary
{
func someMethod()
{
for (key, value) in self
{
var valueRef = _reflect(value)
while valueRef.disposition == .Optional && valueRef.count > 0 && valueRef[0].0 == "Some"
{
valueRef = valueRef[0].1
}
if let valueString: String = valueRef.value as? String
{
print(" \(key) = \(valueString)")
}
else
{
print(" \(key) = \(value) cannot be cast to `String`")
}
}
}
}
let dictionary: [String : AnyObject?] = ["foo" : "bar"]
dictionary.someMethod()
Returns
foo = bar
let dictionary: [String : AnyObject?] = ["foo" : nil]
dictionary.someMethod()
Returns
foo = nil cannot be cast to `String`
let dictionary: [String : AnyObject?] = ["foo" : UIViewController()]
dictionary.someMethod()
Returns
foo = Optional(<UIViewController: 0x7fee7e819870>) cannot be cast to `String`
Dictionary extension in Swift is not recognized
There is no need to constrain Dictionary Value type at all:
extension Dictionary where Key: ExpressibleByStringLiteral {
var jsonString: String? {
guard let data = try? JSONSerialization.data(withJSONObject: self)
else { return nil }
return String(data: data, encoding: .utf8)
}
}
How to create Dictionary extension
You're almost done, just make right constraint on the Key
type:
extension Dictionary where Key == String {
func getInAmountFormat(str: String) -> String? {
if let value = self[str] as? Double {
return String(format: "%.2f", value)
}
return nil
}
}
Also, here is an useful answer.
How to remove dictionary[String:AnyObject] for array using filter function in swift?
Try using this
var globalCountArray = [AnyObject]()
var assetDictionary = [String:AnyObject]()
globalCountArray.append(assetDictionary as AnyObject)
let dict = [String:AnyObject]()
globalCountArray = globalCountArray.filter({ (obj) -> Bool in
if obj is[String:AnyObject] {
return (obj as! [String:AnyObject]) != dict
}
return false
})
--------- OR You can achieve the same via ----------
globalCountArray = globalCountArray.filter({ (obj) -> Bool in
if obj is[String:AnyObject] {
return (obj as! [String:AnyObject]) == dict
}
return true
})
You need to add this method to outside your class definition.
public func !=(lhs: [String: AnyObject], rhs: [String: AnyObject] ) -> Bool {
return !NSDictionary(dictionary: lhs).isEqual(to: rhs)
}
public func ==(lhs: [String: AnyObject], rhs: [String: AnyObject] ) -> Bool {
return NSDictionary(dictionary: lhs).isEqual(to: rhs)
}
Swift: Constrained extension on Dictionary by Element
Element
is a tuple:
typealias Element = (Key, Value)
That cannot match the type you're trying to compare it to (a Dictionary). You can't even say something like where Element:(String, AnyObject)
because tuples don't subtype that way. For example, consider:
var x: (CustomStringConvertible, CustomStringConvertible) = (1,1)
var y: (Int, Int) = (1,1)
x = y // Cannot express tuple conversion '(Int, Int)' to ('CustomStringConvertible', 'CustomStringConvertible')
Compare:
var x1:CustomStringConvertible = 1
var y1:Int = 1
x1 = y1 // No problem
I suspect you get "undeclared type" is because Element
is no longer an unbound type parameter, it's a bound type parameter. Dictionary
is conforming to SequenceType
here. So you can't parameterize on it (at least not in one step; you have to chase it through another layer of type parameters to discover it's "ultimately" unbound). That seems a bad error message, but I suspect it bubbles out of "undeclared type out of the list of types that could possibly be used here." I think that's worth opening a radar on for a better error message.
Instead, I think you mean this:
extension Dictionary where Key: String, Value: AnyObject { }
EDIT for Swift 2:
This is no longer legal Swift. You can only constrain based on protocols. The equivalent code would be:
protocol JSONKey {
func toString() -> String
}
extension String: JSONKey {
func toString() -> String { return self }
}
extension Dictionary where Key: JSONKey, Value: AnyObject { ... }
Dictionary extension to convert nil values to NSNull
You can't add nil to a dict. So you have to force it in there with a cast to someType?
just so you have a key.
Borrowing from this Q/A for the OptionalConvertible solution:
protocol OptionalConvertible {
typealias WrappedValueType = AnyObject
func toOptional() -> WrappedValueType?
}
extension Optional: OptionalConvertible {
typealias WrappedValueType = Wrapped
// just to cast `Optional<Wrapped>` to `Wrapped?`
func toOptional() -> WrappedValueType? {
return self
}
}
extension Dictionary where Value: OptionalConvertible, Key: NSCopying {
//dict: Dictionary<Key, Optional<Value>>
func convertToNSDictionary() -> NSDictionary {
let mutableDict : NSMutableDictionary = NSMutableDictionary()
for key in self.keys {
if let maybeValue = self[key] {
if let value = maybeValue.toOptional() {
mutableDict[key] = value as? AnyObject
} else {
mutableDict[key] = NSNull()
}
}
}
return mutableDict
}
}
var optionalObject : UIView? = nil
var dict : [NSString:AnyObject?] = [:]
dict["alpha"] = 1
dict["beta"] = 2
dict["delta"] = optionalObject as AnyObject? // force a nil into the dict
dict // ["beta": {Some 2}, "alpha": {Some 1}, "delta": nil]
let nsdict = dict.convertToNSDictionary() // ["alpha": 1, "beta": 2, "delta": {NSObject}]
Or a more practical approach :
extension NSDictionary {
static func fromDictionary<Key: Hashable, Value:AnyObject where Key: NSCopying>(dictionary:Dictionary<Key, Value>) -> NSDictionary {
let mutableDict : NSMutableDictionary = NSMutableDictionary()
for key in dictionary.keys {
if let value = dictionary[key] {
mutableDict[key] = value
} else {
mutableDict[key] = NSNull()
}
}
return mutableDict
}
static func fromDictionary<Key: Hashable, Value:AnyObject where Key: NSCopying>(dict: Dictionary<Key, Optional<Value>>) -> NSDictionary {
let mutableDict : NSMutableDictionary = NSMutableDictionary()
for key in dict.keys {
if let maybeValue = dict[key] {
if let value = maybeValue {
mutableDict[key] = value
} else {
mutableDict[key] = NSNull()
}
}
}
return mutableDict
}
}
Related Topics
Is Swiftui Backwards-Compatible With iOS 12.X and Older
Multiple Workers in Swift Command Line Tool
What Are the Rules for Spaces in Swift
Navigationview Pops Back to Root, Omitting Intermediate View
Access Input from Uialertcontroller
How to Create an Instance of a Class from a String in Swift
Using Foreach Loop with Binding Causes Index Out of Range When Array Shrinks (Swiftui)
Swift: Decode Imprecise Decimal Correctly
How to Access a Shadowed Top Level Function in Swift
Simple Swift Fibonacci Program Crashing (Project Euler 2)
Swift: Failing to Copy Files to a Newly Created Folder
Reading Data into a Struct in Swift
Fixing Nsurlconnection Deprecation from Swift 1.2 to 2.0
Hide Navigation Bar Without Losing Swipe Back Gesture in Swiftui
Generating Resource_Bundle_Accessor, Type 'Bundle' Has No Member 'Module'
Is There a Prefix Header (Or Something with This Functionality) in Swift