CFString! is not convertible to String in swift 1.2 - iphone

There is this function in Alamofire
func escape(string: String) -> String {
let legalURLCharactersToBeEscaped: CFStringRef = ":/?&=;+!##$()',*"
return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, legalURLCharactersToBeEscaped, CFStringBuiltInEncodings.UTF8.rawValue)
}
Complier show "CFString! is not convertible to String" error in this func. I have tried Convert CFString to NSString - Swift to cast this , but have no luck.

From the Xcode 6.3 Release Notes:
The implicit conversions from bridged Objective-C classes (NSString/NSArray/NSDictionary) to their corresponding Swift value types (String/Array/Dictionary) have been removed, making the Swift type system simpler and more predictable.
...
In order to perform such a bridging conversion, make the conversion explicit with the as keyword.
You have to convert CFString/NSString to a Swift String explicitly:
func escape(string: String) -> String {
let legalURLCharactersToBeEscaped: CFStringRef = ":/?&=;+!##$()',*"
return CFURLCreateStringByAddingPercentEscapes(nil, string,
nil, legalURLCharactersToBeEscaped,
CFStringBuiltInEncodings.UTF8.rawValue) as String
// HERE ---^
}
The conversion in the other direction (Swift String to NSString) is still done automatically, that's why the the string parameter of your
function can be passed directly to the
CFURLCreateStringByAddingPercentEscapes() function which expects
a CFString argument.

Related

Double primitive type is "AnyObject" however it cannot conform to protocols that require an AnyObject type [duplicate]

I read inline documentation of Swift and I am bit confused.
1) Any is a protocol that all types implicitly conform.
2) AnyObject is a protocol to which all classes implicitly conform.
3) Int, Float, Double are structs
Here is a sample code:
import UIKit
func passAnyObject(param: AnyObject) {
print(param)
}
class MyClass {}
struct MyStruct {}
let a: Int = 1
let b = 2.0
let c = NSObject()
let d = MyClass()
let e = MyStruct()
passAnyObject(a)
passAnyObject(b)
passAnyObject(c)
passAnyObject(d)
//passAnyObject(e) // Argument type 'MyStruct' does not conform to expected type 'AnyObject'
if a is AnyObject { // b, d, e is also AnyObject
print("\(a.dynamicType) is AnyObject")
}
What I don't understand is why Int, Double, Float are AnyObjects? Why compiler doesn't say anything? Those types are declared as structs. Struct MyStruct cannot be passed to the method on the top because it does not conform to AnyObject.
Could you help me understand why Int, Double and Float are AnyObject or why compiler thinks they are?
Because you have Foundation imported, Int, Double, and Float get converted to NSNumber when passed to a function taking an AnyObject. Type String gets converted to NSString. This is done to make life easier when calling Cocoa and Cocoa Touch based interfaces. If you remove import UIKit (or import Cocoa for OS X), you will see:
error: argument type 'Int' does not conform to expected type 'AnyObject'
when you call
passAnyObject(a)
This implicit conversion of value types to objects is described here.
Update for Swift 3 (Xcode 8 beta 6):
Passing an Int, Double, String, or Bool to a parameter of type AnyObject now results in an error such as Argument of type 'Int' does not conform to expected type 'AnyObject'.
With Swift 3, implicit type conversion has been removed. It is now necessary to cast Int, Double, String and Bool with as AnyObject in order to pass it to a parameter of type AnyObject:
let a = 1
passAnyObject(a as AnyObject)
Good find! UIKit actually converts them to NSNumber - also mentioned by #vacawama. The reason for this is, sometimes you're working with code that returns or uses AnyObject, this object could then be cast (as!) as an Int or other "structs".
class Test {
static func test() {
let anyObjectsValues: [AnyObject] = [1, "Two", 3, "Four"] as [AnyObject]
anyObjectsValues.forEach { (value) in
switch value {
case is Int:
print("\(value) is an Int!")
case is String:
print("\(value) is a String!")
default:
print("\(value) is some other type!")
}
}
}
}
I have not imported UIKit or Foundation frameworks. Why compiler is not giving any error? Even it printing the result.
Output:
1 is an Int!
Two is a String!
3 is an Int!
Four is a String!
Does anybody have an idea?

Can you overload type-casting operators in Swift?

I'd like to implement automatic type conversions between known types in Swift. The C# way of doing it has been overloading type-casting operators. If I want my X type to be cross-assignable with, say, string, I would write:
public class X
{
public static implicit operator string(X value)
{
return value.ToString();
}
public static implicit operator X(string value)
{
return new X(value);
}
}
After that I could write stuff like:
string s = new X();
X myObj = s;
and they would be automatically converted. Is that possible in any way in Swift?
No, the language doesn't provide such functionality for custom types. There is bridging between Objective-C collections and Swift collections but that's baked in and not customizable.
// Swift array of `String` elements
let swiftArray: [String] = ["Bob", "John"]
// Obj-C array of `NSString` elements, but element type information
// is not known to the compiler, so it behaves like an opaque NSArray
let nsArray: NSArray = ["Kate", "Betty"]
// Obj-C array of an `NSString` and an `NSNumber`, element type
// information is not known to the compiler
let heterogeneousNSArray: NSArray = ["World", 3]
// Casting with `as` is enough since we're going from Swift array to NSArray
let castedNSArray: NSArray = swiftArray as NSArray
// Force casting with `as!` is required as element type information
// of Obj-C array can not be known at compile time
let castedSwiftArray: [String] = nsArray as! [String]
// Obj-C arrays can not contain primitive data types and can only
// contain objects, so we can cast with `as` without requiring a
// force-cast with `!` if we want to cast to [AnyObject]
let heterogeneousCastedNSArray: [AnyObject] = heterogeneousNSArray as [AnyObject]
Documentation for type casting is available here.
I think you can achieve what you want to do with initializers.
extension X {
init(string: String) {
self = X(string)
}
}
extension String {
init(x: X) {
// toString is implemented elsewhere
self = x.toString
}
}
let x = X()
let string = "Bobby"
let xFromString: X = X(string: string)
let stringFromX: String = String(x: x)
Not directly related to your question but there is also a family of protocols that start with ExpressibleBy..., enabling you to do things like the following:
Let's say we want to initialize strings from integer literals. We can do that by conforming to and implementing ExpressibleByIntegerLiteral
// Strings can not be initialized directly from integer literals
let s1: String = 3 // Error: Can not convert value of type 'Int' to specified type 'String'
// Conform to `ExpressibleByIntegerLiteral` and implement it
extension String: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
// String has an initializer that takes an Int, we can use that to
// create a string
self = String(value)
}
}
// No error, s2 is the string "4"
let s2: String = 4
A nice use case for ExpressibleByStringLiteral can be found here.

Casting from Any to Double swift

I have a simple question, I have this dictionary:
let dict: [String: Any] = ["Area": "100", "YessorNo" : true]
And, for the key area, I want to cast it's value to a double, like so:
let a = dict["Area"] as? Double
When I print a, I get a nil, why? the value 100 is although a string but it is a number isn't? why can't I cast it to a double?
You can't directly cast a String to a Double, you need to use the proper initializer.
guard let numStr = dict["Area"] as? String else {
return
}
let a = Double(numStr)
First, cast from Any to String, and then use an initializer to convert it to Double.
if let a = dict["Area"] as? String, let aDouble = Double(a) {
print(aDouble)
}
Since the other answers provided the code, I will focus on the why of the question. Type casting won't work because, according to the Swift docs, type casting allows you to "treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy." Since a double is not a subclass or a superclass of a string, you can't cast a string to a double even if that string is a string of a number. This is why trying to cast a string to a double returns nil.

Swift 3: Cannot convert value of type 'NSMutableDictionary' to expected argument type '[AnyHashable : Any]!'

This code worked before Swift 3. (Curse you Swift 3!)
Now it's showing this error against the Flurry.logEvent(eventName, withParameters: userData!) line:
Cannot convert value of type 'NSMutableDictionary' to expected
argument type '[AnyHashable : Any]!'
Casting userData! to [AnyHashable : Any] produces this error:
Cannot convert value of type 'NSMutableDictionary' to type
'[AnyHashable : Any]' in coercion
func logEvent(_ eventName: String, userData: NSMutableDictionary?) {
// Use <userData> or create new one?
var userData = userData
if userData == nil {
userData = NSMutableDictionary()
}
// Set base properties
userData!.setObject(gUser.tofus.count, forKey: "Num Tofus" as NSCopying)
userData!.setObject(gUser.getLifetimeTofus(), forKey: "Num Lifetime Tofus" as NSCopying)
// Call Flurry
DispatchQueue.main.async {
Flurry.logEvent(eventName, withParameters: userData! as [AnyHashable:Any])
}
}
What's the right syntax for Swift 3?
If that Flurry.logEvent(_:withParameters:) takes [AnyHashable: Any], why don't you use it as your local userData?
func logEvent(_ eventName: String, userData: NSMutableDictionary?) {
// Use <userData> or create new one?
var userData = userData as NSDictionary? as? [AnyHashable: Any] ?? [:]
// Set base properties
userData["Num Tofus"] = gUser.tofus.count
userData["Num Lifetime Tofus"] = gUser.getLifetimeTofus()
// Call Flurry
DispatchQueue.main.async {
Flurry.logEvent(eventName, withParameters: userData)
}
}
UPDATE
Xcode 8.1 GM seed including SE-0139 and SE-0140 is out, so the list below is updated.
These are the Objective-C safe types, when set to a [AnyHashable: Any] dictionary (or set in a [Any] array, or simply passed to Any which is a non-null id in Objective-C) in which is passed to Objective-C world:
Swift 3.0.1/Xcode 8.1
Optional values including nil
nil is converted to NSNull, all non-nil Optionals are unwrapped.
(NSNull may not be what you want. Still be careful about nil-checking.)
All numeric types and Bool
Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, as well as
Int, UInt, Double, Float, CGFloat and Bool. These are converted to NSNumber.
String
Converted to NSString.
Array, where Element is Objective-C safe
Converted to NSArray.
Dictionary, where Key and Value are Objective-C safe
Converted to NSDictionary.
Set, where Element is Objective-C safe
Converted to NSSet
NSObject descendent types
Not converted, used as is.
Value types which have counter-part reference types
See the list here.
Value types where NSValue has an initializer for
NSRange,
CGPoint,
CGVector,
CGSize,
CGRect,
CGAffineTransform,
UIEdgeInsets,
UIOffset,
CATransform3D,
CMTime,
CMTimeRange,
CMTimeMapping,
CLLocationCoordinate2D,
MKCoordinateSpan,
SCNVector3,
SCNVector4,
SCNMatrix4.
These types are converted to NSValue. (NSRange was already convertible to NSValue in older Swifts, but not well-documented.)
Bad things (example)
Still some values may be converted to _SwiftValue even in Swift 3.0.1.
Swift only types such as (Swift-only)enum, struct, tuple...
(See this list.)
I haven't checked all wrapper enums and structs, but some of them (for example, Notification.Name to NSString) seem to be safely converted.
Swift 3.0.0/Xcode 8.0
Non-Optional numeric types and Bool
Int, UInt, Double, Float, CGFloat and Bool. These are converted to NSNumber.
Non-Optional String
Converted to NSString.
Non-Optional Array, where Element is Objective-C safe
Converted to NSArray.
Non-Optional Dictionary, where Key and Value are Objective-C safe
Converted to NSDictionary.
Non-Optional Set, where Element is Objective-C safe
Converted to NSSet
Non-Optional NSObject descendent types
Not converted, used as is.
Non-Optional value types which have counter-part reference types
See the list here. (The linked article is updated for Swift 3.0.1.)
Bad things (example)
These may be converted to _SwiftValue, which is completely useless and disastrous in Objective-C world.
Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64
Any Optional values including nil
Swift only types such as (Swift-only)enum, struct, tuple...

Why can't Swift find a Float extension method when called on an integer literal?

I have defined a method on Float called printme, and when I try to call it with an integer literal, Swift fails to find the method:
extension Float {
func printme() {
print("value: \(self)")
}
}
12.printme() // error: value of type 'Int' has no member 'printme'
If I use an explicit cast it works:
(12 as Float).printme() // prints "value: 12.0"
Why, if Float conforms to the IntegerLiteralConvertible protocol, does 12.printme() fail to find the method on Float? It works if the type
is Double, but fails for Int32, UInt, and other types. Why does it work for Double, but not for Float?
Note that the following does work:
func printit(f: Float) {
print("value: \(f)")
}
printit(10) // prints "value: 10.0"
So, it fails when the method is called on the integer literal but not when the integer literal is a parameter to a function.
In Xcode 6.4 it fails in a different way:
12.printme() // error: cannot invoke 'printme' with no arguments
When you don't have an explicit type, Swift assumes either Int or Double. From the Swift book:
For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer ... Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double.
Float is not on the inferred type list for literals. If you change your extension to Double, it works (Xcode 7.1):
extension Double {
func printme() {
print("I'm a Double")
}
}
12.printme()
12.0.printme()
For these kind of extensions I look for protocols all types I want to affect conform too, instead of counting on it that the compiler will play nice and convert Double to Float and the other way around.
IntegerLiteralConvertible works for all, but then you have no access to the numeric value. If you add a constraint to either IntegerType or FloatingPointType you have access to toIntMax() and self.advancedBy(0)
extension IntegerLiteralConvertible where Self : IntegerType {
func printMe() {
print(self.toIntMax())
}
}
extension IntegerLiteralConvertible where Self : FloatingPointType {
func printMe() {
print(self.advancedBy(0))
}
}
let float = Float(10.234234)
float.printMe()
let double = Double(234.234234)
double.printMe()
let int = Int(234234)
int.printMe()
let int16 = Int16(234)
int16.printMe()