NSString and NSDictionary valueForKey - nil? - iphone

How can I put a default value into my string if getting data from an empty key/value in a dictionary.
so [myObject setMyString:[dictionary valueForKey:#"myKey"]];
So then if I did NSString *newString = myObject.myString I would get an unrecognized selector error.
So again, I simply need a way to insert a default string if the key value is empty;

If dictionary is a NSDictionary you should probably use objectForKey as valueForKey is used for KVC. It works for NSDictionary but may bite you if the key collide with some NSDictionary KVC key, e.g. "#allKeys" or "#count".
I think the shortest is probably to do:
[dictionary objectForkey:#"myKey"] ?: #"defaultValue"
There is one terrible way of abusing the existing dictionary methods to produce a get by key or return a default value if you don't want to use a condition for some reason...
[[dictionary objectsForKeys:[NSArray arrayWithObject:#"myKey"]
notFoundMarker:#"defaultValue"]
objectAtIndex:0]
You did not hear it from me :)

What about this?
NSString *value = [dictionary valueForKey:#"myKey"];
if (!value) value = #"defaultValue";
[myObject setMyString:value];

Use [NSNull null] for the general case, and handle it when that is returned.
In your question, you wouldn't get "unrecognised selector"; newString would be set to nil (as opposed to [NSNull null], so I suspect you might have meant something else - perhaps how to set defaults values for NSUserDefaults?

I've done this with a simple NSDictionary extension.
NSDictionary+NSDictionaryExtensions.h
#import <Foundation/Foundation.h>
#interface NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj;
#end
NSDictionary+NSDictionaryExtensions.m
#import "NSDictionary+NSDictionaryExtensions.h"
#implementation NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj
{
id ret = [self objectForKey: aKey];
if ( ret == nil )
return defObj;
else
return ret;
}
#end
I can then access as follows:
NSString* str = [dict objectForKey: #"a_key" defaultObject: #"default"];

try
if ( myObject == nil ) {
[myObject setMyString:#""];
}
or
if ( [dictionary valueForKey:#"myKey"] == nil ) {
[dictionary setObject:#"" forKey:#"myKey"];
}

Whatever default value you assigned to your string it will not make myObject.myString return "unrecognized selector error" - usually the property myString either exists or it does not ('usually' as you can dig into the guts of the Objective-C runtime and play games, but this is rarely (if ever) what you want to do!)
What are you trying to do? If your aim is to throw an exception on myObject.myString not being set then you can do that in the property implementation.
For example, valueForKey; will return nil if there is no value set for a given key, so you can check for that in your property:
- (void) setMyString:(NSString *)value
{ myString = value;
}
- (NSString *) myString
{
if (myString == nil)
#throw [NSException exceptionWithName:#"UnrecognizedSelector" reason:#"No value set for myString" userInfo:nil];
return myString;
}
Notes:
code typed at terminal, may contain typos
code assumes garbage collection/ARC on, if not you need to add appropriate retain/copy/release
But do you really want to throw an exception? You would normally only do so if the string should be set and not being so is an exceptional condition - you don't throw for default values.

As per #Paul Lynch you must check for [NSNull null] apart from nil. It is also advisable to check for the data type you are looking for:
- (id) objectForKey: (id) key withDefault: (id) defaultValue
{
id value = self[key];
if (value == nil || [value isEqual: [NSNull null]] || ![defaultValue isKindOfClass: [value class]])
{
value = defaultValue;
}
return value;
}

You can manually check for nil values as below for different types:
extension NSDictionary {
func convertToString() -> String {
let jsonData = try! JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted) as NSData!
if jsonData == nil{
return "{}"
}else {
return String(data: jsonData as! Data, encoding: String.Encoding.utf8)!
}
}
func object_forKeyWithValidationForClass_Int(aKey: String) -> Int {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Int()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Int()
}
} else {
// KEY NOT FOUND
return Int()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Int()
}
else if(aValue.isKind(of: NSString.self)){
return Int((aValue as! NSString).intValue)
}
else {
if aValue is Int {
return self.object(forKey: aKey) as! Int
}
else{
return Int()
}
}
}
func object_forKeyWithValidationForClass_CGFloat(aKey: String) -> CGFloat {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return CGFloat()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return CGFloat()
}
} else {
// KEY NOT FOUND
return CGFloat()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return CGFloat()
}
else {
if aValue is CGFloat {
return self.object(forKey: aKey) as! CGFloat
}
else{
return CGFloat()
}
}
}
func object_forKeyWithValidationForClass_String(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%f", (aValue as! NSNumber).doubleValue)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_StringInt(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%d", (aValue as! NSNumber).int64Value)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_Bool(aKey: String) -> Bool {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Bool()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Bool()
}
} else {
// KEY NOT FOUND
return Bool()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Bool()
}
else {
if aValue is Bool {
return self.object(forKey: aKey) as! Bool
}
else{
return Bool()
}
}
}
func object_forKeyWithValidationForClass_NSArray(aKey: String) -> NSArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSArray()
}
} else {
// KEY NOT FOUND
return NSArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSArray()
}
else {
if aValue is NSArray {
return self.object(forKey: aKey) as! NSArray
}
else{
return NSArray()
}
}
}
func object_forKeyWithValidationForClass_NSMutableArray(aKey: String) -> NSMutableArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableArray()
}
} else {
// KEY NOT FOUND
return NSMutableArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableArray()
}
else {
if aValue is NSMutableArray {
return self.object(forKey: aKey) as! NSMutableArray
}
else{
return NSMutableArray()
}
}
}
func object_forKeyWithValidationForClass_NSDictionary(aKey: String) -> NSDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSDictionary()
}
} else {
// KEY NOT FOUND
return NSDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSDictionary()
}
else {
if aValue is NSDictionary {
return self.object(forKey: aKey) as! NSDictionary
}
else{
return NSDictionary()
}
}
}
func object_forKeyWithValidationForClass_NSMutableDictionary(aKey: String) -> NSMutableDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableDictionary()
}
} else {
// KEY NOT FOUND
return NSMutableDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableDictionary()
}
else {
if aValue is NSMutableDictionary {
return self.object(forKey: aKey) as! NSMutableDictionary
}
else{
return NSMutableDictionary()
}
}
}
}

Related

Check Dictionary to containing nil values and empty values

I want to check my dictionary to containing nil or empty value (nil and ""), add show it on the UI
my dictionary contains string and int values
let params = [
"token":APItoken.getToken(),
"gender":gender_id,
"car_number":number_car,
"car_model":car_model,
"year_of_birth":1998,
"car_year":create_year,
"seats_number":sits,
"facilities":fac,
"type":typeID
] as [String : Any]
I try to use this code, but it doesn't work
if params.values.filter({ $0 == nil }).isEmpty
{
print("full")
}
else
{
print("empty")
}
Change the type of Dictionary from [String:Any] to [String:Any?] to compare values to nil
let someDict = ["first":"name","second":1,"third":1.2,"someNilValue":nil] as [String:Any?]
func checkEmptyDict(_ dict:[String:Any?]) -> Bool {
for (_,value) in dict {
if value == nil || value as? String == "" { return true }
}
return false
}
checkEmptyDict(someDict) //returns true
you should change params type [String : Any] to [String : Any?]
your Code for check nil is correct just need to add empty string condition
like :
if params.values.filter({
if let x = $0 {
if let str = x as? String , str.isEmpty {
return true
} else {
return false
}
} else {
return true
}
}).isEmpty
{
print("not contain nil value ")
}
else
{
print("contain nil value ")
}

Swift 2 to 3 Migration for Swift Sequence Protocol

I'm attempting to convert the following code from this library (https://github.com/dankogai/swift-json) into Swift 3 Compatible code.
I'm having a tough time figuring out how to convert the Sequence protocol used in Swift 2 with the correct version for Swift 3. I can't find any documentation on Swift 2 Sequence protocol changes as compared to 3.
Here is the code that I currently have converted as much as possible to Swift 3
extension JSON : Sequence {
public func generate()->AnyIterator<(AnyObject,JSON)> {
switch _value {
case let o as NSArray:
var i = -1
return AnyIterator {
i=i+1
if i == o.count { return nil }
return (i as AnyObject, JSON(o[i]))
}
case let o as NSDictionary:
var ks = Array(o.allKeys.reversed())
return AnyIterator {
if ks.isEmpty { return nil }
if let k = ks.removeLast() as? String {
return (k as AnyObject, JSON(o.value(forKey: k)!))
} else {
return nil
}
}
default:
return AnyIterator{ nil }
}
}
public func mutableCopyOfTheObject() -> AnyObject {
return _value.mutableCopy as AnyObject
}
}
The error I'm getting in specifics is in attached image.
If you want to play around with it the entire code is rather short for the JSON library. Here it is below:
//
// json.swift
// json
//
// Created by Dan Kogai on 7/15/14.
// Copyright (c) 2014 Dan Kogai. All rights reserved.
//
import Foundation
/// init
public class JSON {
public let _value:AnyObject
/// unwraps the JSON object
public class func unwrap(obj:AnyObject) -> AnyObject {
switch obj {
case let json as JSON:
return json._value
case let ary as NSArray:
var ret = [AnyObject]()
for v in ary {
ret.append(unwrap(obj: v as AnyObject))
}
return ret as AnyObject
case let dict as NSDictionary:
var ret = [String:AnyObject]()
for (ko, v) in dict {
if let k = ko as? String {
ret[k] = unwrap(obj: v as AnyObject)
}
}
return ret as AnyObject
default:
return obj
}
}
/// pass the object that was returned from
/// NSJSONSerialization
public init(_ obj:Any) { self._value = JSON.unwrap(obj: obj as AnyObject) }
/// pass the JSON object for another instance
public init(_ json:JSON){ self._value = json._value }
}
/// class properties
extension JSON {
public typealias NSNull = Foundation.NSNull
public typealias NSError = Foundation.NSError
public class var null:NSNull { return NSNull() }
/// constructs JSON object from data
public convenience init(data:NSData) {
var err:NSError?
var obj:Any?
do {
obj = try JSONSerialization.jsonObject(
with: data as Data, options:[])
} catch let error as NSError {
err = error
obj = nil
}
self.init(err != nil ? err! : obj!)
}
/// constructs JSON object from string
public convenience init(string:String) {
let enc:String.Encoding = String.Encoding.utf8
self.init(data: string.data(using: enc)! as NSData)
}
/// parses string to the JSON object
/// same as JSON(string:String)
public class func parse(string:String)->JSON {
return JSON(string:string)
}
/// constructs JSON object from the content of NSURL
public convenience init(nsurl:NSURL) {
var enc:String.Encoding = String.Encoding.utf8
do {
let str = try NSString(contentsOf:nsurl as URL, usedEncoding:&enc.rawValue)
self.init(string:str as String)
} catch let err as NSError {
self.init(err)
}
}
/// fetch the JSON string from NSURL and parse it
/// same as JSON(nsurl:NSURL)
public class func fromNSURL(nsurl:NSURL) -> JSON {
return JSON(nsurl:nsurl)
}
/// constructs JSON object from the content of URL
public convenience init(url:String) {
if let nsurl = NSURL(string:url) as NSURL? {
self.init(nsurl:nsurl)
} else {
self.init(NSError(
domain:"JSONErrorDomain",
code:400,
userInfo:[NSLocalizedDescriptionKey: "malformed URL"]
)
)
}
}
/// fetch the JSON string from URL in the string
public class func fromURL(url:String) -> JSON {
return JSON(url:url)
}
/// does what JSON.stringify in ES5 does.
/// when the 2nd argument is set to true it pretty prints
public class func stringify(obj:AnyObject, pretty:Bool=false) -> String! {
if !JSONSerialization.isValidJSONObject(obj) {
let error = JSON(NSError(
domain:"JSONErrorDomain",
code:422,
userInfo:[NSLocalizedDescriptionKey: "not an JSON object"]
))
return JSON(error).toString(pretty: pretty)
}
return JSON(obj).toString(pretty: pretty)
}
}
/// instance properties
extension JSON {
/// access the element like array
public subscript(idx:Int) -> JSON {
switch _value {
case _ as NSError:
return self
case let ary as NSArray:
if 0 <= idx && idx < ary.count {
return JSON(ary[idx])
}
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\(idx)] is out of range"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an array"
]))
}
}
/// access the element like dictionary
public subscript(key:String)->JSON {
switch _value {
case _ as NSError:
return self
case let dic as NSDictionary:
if let val:Any = dic[key] { return JSON(val) }
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\"\(key)\"] not found"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an object"
]))
}
}
/// access json data object
public var data:AnyObject? {
return self.isError ? nil : self._value
}
/// Gives the type name as string.
/// e.g. if it returns "Double"
/// .asDouble returns Double
public var type:String {
switch _value {
case is NSError: return "NSError"
case is NSNull: return "NSNull"
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C": return "Bool"
case "q", "l", "i", "s": return "Int"
case "Q", "L", "I", "S": return "UInt"
default: return "Double"
}
case is NSString: return "String"
case is NSArray: return "Array"
case is NSDictionary: return "Dictionary"
default: return "NSError"
}
}
/// check if self is NSError
public var isError: Bool { return _value is NSError }
/// check if self is NSNull
public var isNull: Bool { return _value is NSNull }
/// check if self is Bool
public var isBool: Bool { return type == "Bool" }
/// check if self is Int
public var isInt: Bool { return type == "Int" }
/// check if self is UInt
public var isUInt: Bool { return type == "UInt" }
/// check if self is Double
public var isDouble: Bool { return type == "Double" }
/// check if self is any type of number
public var isNumber: Bool {
if let o = _value as? NSNumber {
let t = String(cString:o.objCType)
return t != "c" && t != "C"
}
return false
}
/// check if self is String
public var isString: Bool { return _value is NSString }
/// check if self is Array
public var isArray: Bool { return _value is NSArray }
/// check if self is Dictionary
public var isDictionary: Bool { return _value is NSDictionary }
/// check if self is a valid leaf node.
public var isLeaf: Bool {
return !(isArray || isDictionary || isError)
}
/// gives NSError if it holds the error. nil otherwise
public var asError:NSError? {
return _value as? NSError
}
/// gives NSNull if self holds it. nil otherwise
public var asNull:NSNull? {
return _value is NSNull ? JSON.null : nil
}
/// gives Bool if self holds it. nil otherwise
public var asBool:Bool? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C": return Bool(o.boolValue)
default:
return nil
}
default: return nil
}
}
/// gives Int if self holds it. nil otherwise
public var asInt:Int? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int(o.int64Value)
}
default: return nil
}
}
/// gives Int32 if self holds it. nil otherwise
public var asInt32:Int32? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int32(o.int64Value)
}
default: return nil
}
}
/// gives Int64 if self holds it. nil otherwise
public var asInt64:Int64? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int64(o.int64Value)
}
default: return nil
}
}
/// gives Float if self holds it. nil otherwise
public var asFloat:Float? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Float(o.floatValue)
}
default: return nil
}
}
/// gives Double if self holds it. nil otherwise
public var asDouble:Double? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Double(o.doubleValue)
}
default: return nil
}
}
// an alias to asDouble
public var asNumber:Double? { return asDouble }
/// gives String if self holds it. nil otherwise
public var asString:String? {
switch _value {
case let o as NSString:
return o as String
default: return nil
}
}
/// if self holds NSArray, gives a [JSON]
/// with elements therein. nil otherwise
public var asArray:[JSON]? {
switch _value {
case let o as NSArray:
var result = [JSON]()
for v:Any in o { result.append(JSON(v)) }
return result
default:
return nil
}
}
/// if self holds NSDictionary, gives a [String:JSON]
/// with elements therein. nil otherwise
public var asDictionary:[String:JSON]? {
switch _value {
case let o as NSDictionary:
var result = [String:JSON]()
for (ko, v): (Any, Any) in o {
if let k = ko as? String {
result[k] = JSON(v)
}
}
return result
default: return nil
}
}
/// Yields date from string
public var asDate:NSDate? {
if let dateString = _value as? String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
return dateFormatter.date(from: dateString) as NSDate?
}
return nil
}
/// gives the number of elements if an array or a dictionary.
/// you can use this to check if you can iterate.
public var count:Int {
switch _value {
case let o as NSArray: return o.count
case let o as NSDictionary: return o.count
default: return 0
}
}
public var length:Int { return self.count }
// gives all values content in JSON object.
public var allValues:JSON{
if(self._value.allValues == nil) {
return JSON([])
}
return JSON(self._value.allValues)
}
// gives all keys content in JSON object.
public var allKeys:JSON{
if(self._value.allKeys == nil) {
return JSON([])
}
return JSON(self._value.allKeys)
}
}
extension JSON : Sequence {
public func generate()->AnyIterator<(AnyObject,JSON)> {
switch _value {
case let o as NSArray:
var i = -1
return AnyIterator {
i=i+1
if i == o.count { return nil }
return (i as AnyObject, JSON(o[i]))
}
case let o as NSDictionary:
var ks = Array(o.allKeys.reversed())
return AnyIterator {
if ks.isEmpty { return nil }
if let k = ks.removeLast() as? String {
return (k as AnyObject, JSON(o.value(forKey: k)!))
} else {
return nil
}
}
default:
return AnyIterator{ nil }
}
}
public func mutableCopyOfTheObject() -> AnyObject {
return _value.mutableCopy as AnyObject
}
}
extension JSON : CustomStringConvertible {
/// stringifies self.
/// if pretty:true it pretty prints
public func toString(pretty:Bool=false)->String {
switch _value {
case is NSError: return "\(_value)"
case is NSNull: return "null"
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return o.boolValue.description
case "q", "l", "i", "s":
return o.int64Value.description
case "Q", "L", "I", "S":
return o.uint64Value.description
default:
switch o.doubleValue {
case 0.0/0.0: return "0.0/0.0" // NaN
case -1.0/0.0: return "-1.0/0.0" // -infinity
case +1.0/0.0: return "+1.0/0.0" // infinity
default:
return o.doubleValue.description
}
}
case let o as NSString:
return o.debugDescription
default:
let opts = pretty ? JSONSerialization.WritingOptions.prettyPrinted : JSONSerialization.WritingOptions()
if let data = (try? JSONSerialization.data(
withJSONObject: _value, options:opts)) as NSData? {
if let result = NSString(
data:data as Data, encoding:String.Encoding.utf8.rawValue
) as? String {
return result
}
}
return "YOU ARE NOT SUPPOSED TO SEE THIS!"
}
}
public var description:String { return toString() }
}
extension JSON : Equatable {}
public func ==(lhs:JSON, rhs:JSON)->Bool {
// print("lhs:\(lhs), rhs:\(rhs)")
if lhs.isError || rhs.isError { return false }
else if lhs.isLeaf {
if lhs.isNull { return lhs.asNull == rhs.asNull }
if lhs.isBool { return lhs.asBool == rhs.asBool }
if lhs.isNumber { return lhs.asNumber == rhs.asNumber }
if lhs.isString { return lhs.asString == rhs.asString }
}
else if lhs.isArray {
for i in 0..<lhs.count {
if lhs[i] != rhs[i] { return false }
}
return true
}
else if lhs.isDictionary {
for (k, v) in lhs.asDictionary! {
if v != rhs[k] { return false }
}
return true
}
fatalError("JSON == JSON failed!")
}
In Swift 3, generate() has been renamed to makeIterator(). Changing the name of your function should fix the problem. (Note that other names have also changed, like AnyGenerator → AnyIterator, but it looks like that one has already been taken care of in your code.)
This change was implemented as part of SE-0006: Apply API Guidelines to the Standard Library.

Dictionary extension to convert nil values to NSNull

Since you can't cast a Dictionary<String, AnyObject?> into a NSDictionary directly, I want to write a Dictionary extension that will do that conversion (substituting NSNull for any nils).
But in order to do that, my Dictionary extension must be constrained to dicts whose values are Optional<T> where T:AnyObject. How do I write the type constraint for that?
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
}
}

Can I use generics to cast NSNumber to T in swift?

What I want
func safeGet<T>() -> T {
let value = magic()
if let typedValue = value as? T {
return typedValue
}
}
The reason this doesn't work is the fact that you can't do <NSNumber> as Int in swift
What do I put in the <what do I put here?> placeholder?
func safeGet<T>() -> T {
let value = magic()
if let typedValue = value as? NSNumber {
return <what do I put here?>
} else if let typedValue = value as? T {
return typedValue
}
}
In the end I did this to be able to get typed values from the dictionary in a way that throws errors. It's used like this
let name:String = dictionary.safeGet("name")
or
let name = dictionary.safeGet("name") as String`
The source code:
import Foundation
extension Dictionary {
func safeGet<T>(key:Key) throws -> T {
if let value = self[key] as? AnyObject {
if let typedValue = value as? T {
return typedValue
}
let typedValue: T? = parseNumber(value)
if typedValue != nil {
return typedValue!
}
let typeData = Mirror(reflecting: value)
throw generateNSError(
domain: "DictionaryError.WrongType",
message: "Could not convert `\(key)` to `\(T.self)`, it was `\(typeData.subjectType)` and had the value `\(value)`"
)
} else {
throw generateNSError(
domain: "DictionaryError.MissingValue",
message: "`\(key)` was not in dictionary. The dictionary was:\n\(self.description)"
)
}
}
private func parseNumber<T>(value: AnyObject) -> T? {
if Int8.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.charValue as? T
} else if let stringValue = value as? String {
return Int8(stringValue) as? T
}
} else if Int16.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.shortValue as? T
} else if let stringValue = value as? String {
return Int16(stringValue) as? T
}
} else if Int32.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.longValue as? T
} else if let stringValue = value as? String {
return Int32(stringValue) as? T
}
} else if Int64.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.longLongValue as? T
} else if let stringValue = value as? String {
return Int64(stringValue) as? T
}
} else if UInt8.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.unsignedCharValue as? T
} else if let stringValue = value as? String {
return UInt8(stringValue) as? T
}
} else if UInt16.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.unsignedShortValue as? T
} else if let stringValue = value as? String {
return UInt16(stringValue) as? T
}
} else if UInt32.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.unsignedIntValue as? T
} else if let stringValue = value as? String {
return UInt32(stringValue) as? T
}
} else if UInt64.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.unsignedLongLongValue as? T
} else if let stringValue = value as? String {
return UInt64(stringValue) as? T
}
} else if Double.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.doubleValue as? T
} else if let stringValue = value as? String {
return Double(stringValue) as? T
}
} else if Float.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.floatValue as? T
} else if let stringValue = value as? String {
return Float(stringValue) as? T
}
} else if String.self == T.self {
if let numericValue = value as? NSNumber {
return numericValue.stringValue as? T
} else if let stringValue = value as? String {
return stringValue as? T
}
}
return nil
}
private func generateNSError(domain domain: String, message: String) -> NSError {
return NSError(
domain: domain,
code: -1,
userInfo: [
NSLocalizedDescriptionKey: message
])
}
}

How to check object is nil or not in swift?

Suppose I have String like :
var abc : NSString = "ABC"
and I want to check that it is nil or not and for that I try :
if abc == nil{
//TODO:
}
But this is not working and giving me an error. Error Says :
Can not invoke '=='with an argument list of type '(#|value NSString , NilLiteralConvertible)'
Any solution for this?
If abc is an optional, then the usual way to do this would be to attempt to unwrap it in an if statement:
if let variableName = abc { // If casting, use, eg, if let var = abc as? NSString
// variableName will be abc, unwrapped
} else {
// abc is nil
}
However, to answer your actual question, your problem is that you're typing the variable such that it can never be optional.
Remember that in Swift, nil is a value which can only apply to optionals.
Since you've declared your variable as:
var abc: NSString ...
it is not optional, and cannot be nil.
Try declaring it as:
var abc: NSString? ...
or alternatively letting the compiler infer the type.
The case of if abc == nil is used when you are declaring a var and want to force unwrap and then check for null. Here you know this can be nil and you can check if != nil use the NSString functions from foundation.
In case of String? you are not aware what is wrapped at runtime and hence you have to use if-let and perform the check.
You were doing following but without "!". Hope this clears it.
From apple docs look at this:
let assumedString: String! = "An implicitly unwrapped optional string."
You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:
if assumedString != nil {
println(assumedString)
}
// prints "An implicitly unwrapped optional string."
The null check is really done nice with guard keyword in swift. It improves the code readability and the scope of the variables are still available after the nil checks if you want to use them.
func setXYX -> Void{
guard a != nil else {
return;
}
guard b != nil else {
return;
}
print (" a and b is not null");
}
I ended up writing utility function for nil check
func isObjectNotNil(object:AnyObject!) -> Bool
{
if let _:AnyObject = object
{
return true
}
return false
}
Does the same job & code looks clean!
Usage
var someVar:NSNumber?
if isObjectNotNil(someVar)
{
print("Object is NOT nil")
}
else
{
print("Object is nil")
}
func isObjectValid(someObject: Any?) -> Any? {
if someObject is String {
if let someObject = someObject as? String {
return someObject
}else {
return ""
}
}else if someObject is Array<Any> {
if let someObject = someObject as? Array<Any> {
return someObject
}else {
return []
}
}else if someObject is Dictionary<AnyHashable, Any> {
if let someObject = someObject as? Dictionary<String, Any> {
return someObject
}else {
return [:]
}
}else if someObject is Data {
if let someObject = someObject as? Data {
return someObject
}else {
return Data()
}
}else if someObject is NSNumber {
if let someObject = someObject as? NSNumber{
return someObject
}else {
return NSNumber.init(booleanLiteral: false)
}
}else if someObject is UIImage {
if let someObject = someObject as? UIImage {
return someObject
}else {
return UIImage()
}
}
else {
return "InValid Object"
}
}
This function checks any kind of object and return's default value of the kind of object, if object is invalid.
if (MyUnknownClassOrType is nil) {
println("No class or object to see here")
}
Apple also recommends that you use this to check for depreciated and removed classes from previous frameworks.
Here's an exact quote from a developer at Apple:
Yes. If the currently running OS doesn’t implement the class then the class method will return nil.
Hope this helps :)
Normally, I just want to know if the object is nil or not.
So i use this function that just returns true when the object entered is valid and false when its not.
func isNotNil(someObject: Any?) -> Bool {
if someObject is String {
if (someObject as? String) != nil {
return true
}else {
return false
}
}else if someObject is Array<Any> {
if (someObject as? Array<Any>) != nil {
return true
}else {
return false
}
}else if someObject is Dictionary<AnyHashable, Any> {
if (someObject as? Dictionary<String, Any>) != nil {
return true
}else {
return false
}
}else if someObject is Data {
if (someObject as? Data) != nil {
return true
}else {
return false
}
}else if someObject is NSNumber {
if (someObject as? NSNumber) != nil{
return true
}else {
return false
}
}else if someObject is UIImage {
if (someObject as? UIImage) != nil {
return true
}else {
return false
}
}
return false
}
Swift 4.2
func isValid(_ object:AnyObject!) -> Bool
{
if let _:AnyObject = object
{
return true
}
return false
}
Usage
if isValid(selectedPost)
{
savePost()
}
Swift short expression:
var abc = "string"
abc != nil ? doWork(abc) : ()
or:
abc == nil ? () : abc = "string"
or both:
abc != nil ? doWork(abc) : abc = "string"
Swift-5 Very Simple Way
//MARK:- In my case i have an array so i am checking the object in this
for object in yourArray {
if object is NSNull {
print("Hey, it's null!")
}else if object is String {
print("Hey, it's String!")
}else if object is Int {
print("Hey, it's Int!")
}else if object is yourChoice {
print("Hey, it's yourChoice!")
}
else {
print("It's not null, not String, not yourChoice it's \(object)")
}
}
Swift 4
You cannot compare Any to nil.Because an optional can be nil and hence it always succeeds to true.
The only way is to cast it to your desired object and compare it to nil.
if (someone as? String) != nil
{
//your code`enter code here`
}
Swift 5
Crash
Your app crash because parameters receive null, and broke in NSException.
if let parameters = parameters {
httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
}
Solution
if let parameters = parameters, JSONSerialization.isValidJSONObject(parameters) {
httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
}