Get a unique String for a given AnyObject? - swift

In Objective-C, this was as simple as:
[NSString stringWithFormat:#"%p", objRef]
How can I do this in Swift?

func hashString (obj: AnyObject) -> String {
return String(ObjectIdentifier(obj).uintValue)
}
let id = hashString(obj)
Swift 3.0
return String(UInt(ObjectIdentifier(obj))
Swift 4.1
return String(UInt(bitPattern: ObjectIdentifier(obj)))

How about a direct translation:
func pointerToString(objRef: NSObject) -> String {
return NSString(format: "%p", objRef)
}
A more native way (in decimal, not hex):
func pointerToString(objRef: AnyObject) -> String {
return withObjectAtPlusZero(objRef, { ptr in
"\(UnsafePointer<RawByte>(ptr) - nil)"
})
}
func pointerToString(objRef: AnyObject) -> String {
let ptr: COpaquePointer =
Unmanaged<AnyObject>.passUnretained(objRef).toOpaque()
return "\(UnsafePointer<RawByte>(ptr) - nil)"
}
Update: Pointers stringify correctly now, so you can just do
func pointerToString(objRef: AnyObject) -> String {
let ptr: COpaquePointer =
Unmanaged<AnyObject>.passUnretained(objRef).toOpaque()
return "\(ptr)"
}

Swift 4.1
String(UInt(bitPattern: ObjectIdentifier(obj)))
#aleclarson's answer update
func hashString(obj: AnyObject) -> String {
return String(UInt(bitPattern: ObjectIdentifier(obj)))
}
let id = hashString(obj)

what you could do to resolve the error is pretty much this:
func pointerToString<T> (ptr: CMutablePointer<T>) -> String {
// ...
}
but printing the actual pointer is not really possible in Swift.

You can't. A native String in Swift is an object with a different and opaque memory layout than the contents of whatever memory is located at the CMutablePointer address. So you can't assign one to another. An alternative is to assign/copy an NSString that has been initialized with the contents of the memory at the pointer address.

Related

How can I add a method to NSString in Swift so that it sets the value of Self?

I understand that subclassing NSString is a bad thing, but I'd like to add methods to NSString in Swift so that I can sanitise the string, according to specific rules, before storing its value.
I thought perhaps I could do something really simple like this (no sanitisation in this example - I'm just trying things out at the moment:
import Foundation
extension String{
func setString(setter:String) {
self = setter
}
}
This doesn't work though - 'self' is immutable. From looking at the docs, this would be valid for an initialiser - but I don't necessarily want to call this code for all strings.
I can find my way around ObjC - but I'm fashionably late to the party for Swift. Any suggestions?
Update
So this is a more accurate representation of what I'm trying to do (and thank you to everyone who has helped so far)
import Foundation
#objc extension NSString {
func sanitizedFilename() -> String {
let invalidCharacters = CharacterSet(charactersIn: "\\/:*?\"<>|")
.union(.newlines)
.union(.illegalCharacters)
.union(.controlCharacters)
return self.components(separatedBy: invalidCharacters).joined(separator: "")
}
func sanitizedString() -> String {
var invalidCharacters = CharacterSet().union(.illegalCharacters).union(.controlCharacters)
invalidCharacters.remove("\n")
invalidCharacters.remove("\t")
return self.components(separatedBy: invalidCharacters).joined(separator: "")
}
mutating func sanitizeFilename() {
self = self.sanitizedFilename() as NSString
}
mutating func sanitizeString() {
self = self.sanitizedString() as NSString
}
}
If I remove the NSString stuff - keep it as String then it builds, but I can't have #objc and hence I can't use it from Objective C. If I put the NSString stuff in then self is immutable.
I have a feeling that this is a really easy fix for someone who actually knows what they're doing, and that I should probably put my head in a bucket.
Here's something to help you understand this.
import Foundation
extension String {
// returns a new sanitized value (doesn't change anything in caller)
func sanitized() -> String {
return self.replacingOccurrences(of: "(", with: "")
.replacingOccurrences(of: ")", with: "")
}
// Sanitizes self (changes the value of caller)
// mutating is necessary when you need to modify self
mutating func sanitize() {
self = self.sanitized()
}
}
Example usage
let test1 = "(Test)"
let output1 = test1.sanitized() // receive a new value
print(output1) // Test
var test2 = "(Test)"
test2.sanitize() // modify the caller, it has to be var (not let)
print(test2) // Test

Swift ValueTransformer old "good" code now complains with contemporary swift

I have an old simple ValueTransformer. Written just following the conventional pattern to support a GUI interface to edit a specific encoded file format. I recently has cause to regenerate with current compiler and it is complaining bitterly about converting Bool.self to AnyClass. Yeah, OK, I understand that Bool is no longer a Class (if it ever was) it is a frozen Struct. So the question is that of, is there a Swift way of continuing to use this ValueTransformer for a struct rather than a class?
I can see an ugly solution of wrapping a Bool in a Class and using that but is poor design at best, but if needs must....
Am I missing something obvious in the ever changing world ?
The complaint from the the compiler is on the single line in transformedValueClass
return Bool.self as! AnyClass
Cast from 'Bool.Type' to unrelated type 'AnyClass' (aka 'AnyObject.Type') always fails
class StringToBoolTransformer : ValueTransformer
{
var boolValue : Bool?
override func transformedValue(_ value: Any?) -> Any? {
if let stringRep = value as? String
{
if stringRep.count == 1 {
boolValue = (stringRep == "1" ? true :(stringRep == "0" ? false: nil))
}
}
return boolValue
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
var boolAsString : String?
if let boolValue = value as? Bool {
boolAsString = boolValue ? "1" : "0"
}
return boolAsString
}
override class func transformedValueClass() -> AnyClass
{
return Bool.self as! AnyClass
}
override class func allowsReverseTransformation() -> Bool {
return true
}
}
(NS)ValueTransformer relies on Objective-C and the corresponding class of Bool is NSNumber.
I made the code a bit more contemporary 😉
class StringToBoolTransformer : ValueTransformer
{
override func transformedValue(_ value: Any?) -> Any? {
guard let stringRep = value as? String,
stringRep.count == 1,
["0","1"].contains(stringRep) else { return nil }
let boolValue = stringRep == "1"
return NSNumber(booleanLiteral: boolValue)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let number = value as? NSNumber else { return nil }
return number.boolValue ? "1" : "0"
}
override class func transformedValueClass() -> AnyClass
{
return NSNumber.self
}
override class func allowsReverseTransformation() -> Bool {
return true
}
}
In Swift Bool is a struct, NOT a class. So you can never cast it to AnyClass.
What you can try as a workaround is use NSNumber class as a storage for bool via NSNumber.init(value: Bool) and then return NSNumber.self from your implementation.

Swift cast dictionary value as type

I am looking for best way how can I make this code to one line:
if (dictionary["Amoumt"] is Double) {
amount = dictionary["Amount"] as Double
} else {
amount = NSString(string: dictionary["Amount"] as String).doubleValue
}
I have Dictionary<String, AnyObject> and I would like to parse values from it. I am using code like above but it's too many lines. I would like to make it to one line. Something like:
dictionary["Amount"].parseDouble()
There is no problem to create extension with this method:
func parseDouble() -> Double {
if (self is Double) {
return self as Double
} else {
return NSString(string:(self as String)).doubleValue
}
}
But which type should I extend? Next could you help me with generic method? So I could call something like this:
dictionary["Amount"].parse(Double)
And is this good way how to do this or should I do it another way?
You can use AnyObject as is. Try:
var dictionary:[String:AnyObject] = [
"foo": 4.21, // NSNumber
"bar": "42.5", // NSString
"baz": [1,2,3], // NSArray
]
let foo = dictionary["foo"]?.doubleValue ?? 0 // -> 4.21
let bar = dictionary["bar"]?.doubleValue ?? 0 // -> 42.5
let baz = dictionary["baz"]?.doubleValue ?? 0 // -> 0.0
This works because both NSNumber and NSString have .doubleValue property.
On the other hand, NSArray does not have that property, in this case it returns nil.
As described in the document:
You can also call any Objective-C method and access any property without casting to a more specific class type. This includes Objective-C compatible methods marked with the #objc attribute.
Maybe you are looking for this kind of extenison:
extension Dictionary{
func parseDouble(key:Key) -> Double {
let result = self[key]
if (result is Double) {
return result as Double
} else {
return NSString(string:(result as String)).doubleValue
}
}
}
And getting value for key by using this:
var doubleValue = dictionary.parseDouble("amount")
And a generic function
extension Dictionary{
func parse<T>(key:Key) -> T? {
let result = self[key]
if (result is T) {
return result as? T
}
return nil
}
}
var doubleValue:Double? = myDistionary.parse("someKeyForDouble")
var stringValue:String? = myDistionary.parse("someKeyForString")
The easiest way to condense this is to use the nil coalescing operator and an optional double. This attempts to cast the value as a double. If it succeeds, it unwraps it, if it fails, it defaults to the second value, which comes from converting `dict[amount]' to a string and taking its double value.
var amount: Double? = nil
let dict: [String: AnyObject] = ["amount" : "1.2"]
amount = (dict["amount"] as? Double) ?? NSString(string: dict["amount"] as! String).doubleValue
And to make your function:
func getDouble(obj: AnyObject) -> Double {
return (obj as? Double) ?? NSString(string: obj as! String).doubleValue
}
and you call it using getDouble(dict["amount"]). An extension for something like this is probably overkill in my opinion.
If you wanted an extension, the best place to put it in theory would be AnyObject – because it is an AnyObject that you want to convert.
But AnyObject is actually a protocol, so you can't extend it.
I wouldn't recommend putting it as an extension to Dictionary – the coercing of a type into a double is not really anything to do with dictionaries.
So the best approach is to do it as a free function not as an extension:
func getDouble(obj: AnyObject?) -> Double {
return (obj as? Double) ?? (obj as? NSString)?.doubleValue ?? 0
}
asDouble(dictionary["Amount"])
Note, this function is safe if you pass it a function that is neither a double nor a string. Other solutions using as or ! instead of as? will crash at runtime if you ever pass something else in.
You could argue it should return an optional, with nil if the value was not convertible to a double. This is what String.toInt() does. Unfortunately, the limitation of NSString.doubleValue is that it doesn't do this – it defaults to zero instead – so you can't combine these two approaches.

Swift - Cast Int64 to AnyObject for NSMutableArray

Hi I have a NSMutableArray and I try this:
var ma = NSMutableArray()
let number:Int64 = 8345834344
ma.addObject(number)// Error "Type Int64 does not conform to protocol AnyObject"
How to add Int64 variable to NSMutableArray() ?
You are using a Foundation array (NSMutableArray), so you should use a Foundation number object:
ma.addObject(NSNumber(longLong:number))
You could also use a native swift array:
var ma = [Int64]()
ma.append(number)
Like so much of Swift, this is implemented in Swift.
So you can do this (or the equivalent for the types you want) which will magically make it possible to use an Int64 where the language expects an AnyObject:
extension Int64 : _ObjectiveCBridgeable
{
public init(_ number: NSNumber)
{
self.init(number.longLongValue)
}
public func _bridgeToObjectiveC() -> NSNumber
{
return NSNumber(longLong: self)
}
public static func _getObjectiveCType() -> Any.Type
{
return NSNumber.self
}
public static func _isBridgedToObjectiveC() -> Bool
{
return true
}
public static func _forceBridgeFromObjectiveC(source: NSNumber, inout result: Int64?)
{
result = source.longLongValue
}
public static func _conditionallyBridgeFromObjectiveC(source: NSNumber, inout result: Int64?) -> Bool
{
result = source.longLongValue
return true
}
}

Is there a way to set associated objects in Swift?

Coming from Objective-C you can call function objc_setAssociatedObject between 2 objects to have them maintain a reference, which can be handy if at runtime you don't want an object to be destroyed until its reference is removed also. Does Swift have anything similar to this?
Here is a simple but complete example derived from jckarter's answer.
It shows how to add a new property to an existing class. It does it by defining a computed property in an extension block. The computed property is stored as an associated object:
import ObjectiveC
// Declare a global var to produce a unique address as the assoc object handle
private var AssociatedObjectHandle: UInt8 = 0
extension MyClass {
var stringProperty:String {
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! String
}
set {
objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
EDIT:
If you need to support getting the value of an uninitialized property and to avoid getting the error unexpectedly found nil while unwrapping an Optional value, you can modify the getter like this:
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? ""
}
The solution supports all the value types as well, and not only those that are automagically bridged, such as String, Int, Double, etc.
Wrappers
import ObjectiveC
final class Lifted<T> {
let value: T
init(_ x: T) {
value = x
}
}
private func lift<T>(x: T) -> Lifted<T> {
return Lifted(x)
}
func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, policy: objc_AssociationPolicy) {
if let v: AnyObject = value as? AnyObject {
objc_setAssociatedObject(object, associativeKey, v, policy)
}
else {
objc_setAssociatedObject(object, associativeKey, lift(value), policy)
}
}
func getAssociatedObject<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? {
if let v = objc_getAssociatedObject(object, associativeKey) as? T {
return v
}
else if let v = objc_getAssociatedObject(object, associativeKey) as? Lifted<T> {
return v.value
}
else {
return nil
}
}
A possible
Class extension (Example of usage)
extension UIView {
private struct AssociatedKey {
static var viewExtension = "viewExtension"
}
var referenceTransform: CGAffineTransform? {
get {
return getAssociatedObject(self, associativeKey: &AssociatedKey.viewExtension)
}
set {
if let value = newValue {
setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.viewExtension, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
I wrote a modern wrapper available at https://github.com/b9swift/AssociatedObject
You may be surprised that it even supports Swift structures for free.
Obviously, this only works with Objective-C objects. After fiddling around with this a bit, here's how to make the calls in Swift:
import ObjectiveC
// Define a variable whose address we'll use as key.
// "let" doesn't work here.
var kSomeKey = "s"
…
func someFunc() {
objc_setAssociatedObject(target, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN))
let value : AnyObject! = objc_getAssociatedObject(target, &kSomeKey)
}
Update in Swift 3.0
For example this is a UITextField
import Foundation
import UIKit
import ObjectiveC
// Declare a global var to produce a unique address as the assoc object handle
var AssociatedObjectHandle: UInt8 = 0
extension UITextField
{
var nextTextField:UITextField {
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! UITextField
}
set {
objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Klaas answer just for Swift 2.1:
import ObjectiveC
let value = NSUUID().UUIDString
var associationKey: UInt8 = 0
objc_setAssociatedObject(parentObject, &associationKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
let fetchedValue = objc_getAssociatedObject(parentObject, &associationKey) as! String
Just add #import <objc/runtime.h> on your brindging header file to access objc_setAssociatedObject under swift code
The above friend has answered your question, but if it is related to closure properties, please note:
```
import UIKit
public extension UICollectionView {
typealias XYRearrangeNewDataBlock = (_ newData: [Any]) -> Void
typealias XYRearrangeOriginaDataBlock = () -> [Any]
// MARK:- associat key
private struct xy_associatedKeys {
static var originalDataBlockKey = "xy_originalDataBlockKey"
static var newDataBlockKey = "xy_newDataBlockKey"
}
private class BlockContainer {
var rearrangeNewDataBlock: XYRearrangeNewDataBlock?
var rearrangeOriginaDataBlock: XYRearrangeOriginaDataBlock?
}
private var newDataBlock: BlockContainer? {
get {
if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? BlockContainer {
return newDataBlock
}
return nil
}
set(newValue) {
objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: #escaping XYRearrangeOriginaDataBlock, newDataBlock: #escaping XYRearrangeNewDataBlock) {
self.init()
let blockContainer: BlockContainer = BlockContainer()
blockContainer.rearrangeNewDataBlock = newDataBlock
blockContainer.rearrangeOriginaDataBlock = originalDataBlock
self.newDataBlock = blockContainer
}
```
For 2022, now very simple:
// Utils-tags.swift
// Just a "dumb Swift trick" to add a string tag to a view controller.
// For example, with UIDocumentPickerViewController you need to know
// "which button was clicked to launch a picker"
import UIKit
private var _docPicAssociationKey: UInt8 = 0
extension UIDocumentPickerViewController {
public var tag: String {
get {
return objc_getAssociatedObject(self, &_docPicAssociationKey)
as? String ?? ""
}
set(newValue) {
objc_setAssociatedObject(self, &_docPicAssociationKey,
newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}