Swift: How to deallocate properties when init throw? - swift

There is a memory leak with this example code.
The pointer1 and pointer2 allocate before Person inits successfully. If the init function throws an Error. The deinit function will never be executed. So the pointer1 and pointer2 will never be released.
import XCTest
class Person {
// case1
let pointer1: UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>.allocate(capacity: 1)
// case2
let pointer2: UnsafeMutablePointer<Int>
let name: String
init(name: String) throws {
// case2
self.pointer2 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
if name == "UnsupportName" {
throw NSError()
}
self.name = name
}
deinit {
pointer1.deallocate()
pointer2.deallocate()
}
}
class InterestTests: XCTestCase {
func testExample() {
while true {
_ = try? Person(name: "UnsupportName")
}
}
}
Sometimes the logic is very complicated. In my real cases. There are a lot of allocate and throws with if and guard. Some it's hard to control it.
Is there any way to avoid this memory leak?
Here is a similar question: https://forums.swift.org/t/deinit-and-failable-initializers/1199

In your specific example, the solution is straightforward. Don't allocate any memory until you have resolved all possible failures:
class Person {
let aPointer: UnsafeMutablePointer<Int> // Do not allocate here.
let name: String
init(name: String) throws {
// Validate everything here
guard name != "UnsupportName" else {
throw NSError()
}
// After this point, no more throwing:
self.name = name
// Move the allocation here
self.aPointer = UnsafeMutablePointer.allocate(capacity: 1)
}
deinit {
aPointer.deallocate()
}
}
But the more general solution is to use do/catch like anywhere else you need to manage errors:
class Person {
let aPointer = UnsafeMutablePointer<Int>.allocate(capacity: 1)
let name: String
init(name: String) throws {
do {
if name == "UnsupportName" {
throw NSError()
}
self.name = name
} catch let e {
self.aPointer.deallocate()
throw e
}
}
deinit {
aPointer.deallocate()
}
}
I would be tempted to move the .allocate inside the init, just to make it a bit more visible what's going on. The key point is that you should either allocate all your memory first, before anything can throw (so you know you can deallocate it all), or all after the last throw (so you know you don't have anything to deallocate).
Looking at the solution you've added, it's ok, but suggests dangerous logic surrounding it. It would be much better to unwind this to place the allocation into their own objects (which would almost certainly also get rid of the UnsafeMutablePointers; needing a lot of those in a single class is very suspicious).
That said, there are cleaner ways IMO to build the error handling along this path.
extension UnsafeMutablePointer {
static func allocate(capacity: Int, withCleanup cleanup: inout [() -> Void]) -> UnsafeMutablePointer<Pointee> {
let result = allocate(capacity: capacity)
result.addTo(cleanup: &cleanup)
return result
}
func addTo(cleanup: inout [() -> Void]) {
cleanup.append { self.deallocate() }
}
}
This lets UnsafeMutablePointers append cleanup information into an array, rather than creating a lot of defer blocks, which raises the risk of missing one during cleanup.
With that, your init looks like:
init(name: String) throws {
var errorCleanup: [() -> Void] = []
defer { for cleanup in errorCleanup { cleanup() } }
// deallocate helper for case1
pointer1.addTo(cleanup: &errorCleanup)
// case2
self.pointer2 = UnsafeMutablePointer<Int>.allocate(capacity: 1, withCleanup: &errorCleanup)
// case ...
if name == "UnsupportName" {
throw NSError()
}
self.name = name
// In the end. set deallocate helpers to nil
errorCleanup.removeAll()
}
Of course that setups the danger of calling allocate(capacity:) rather than allocate(capacity:withCleanup:). So you could fix that by wrapping it into another type; a reference type that automatically deallocates itself.
class SharedPointer<Pointee> {
let ptr: UnsafeMutablePointer<Pointee>
static func allocate(capacity: Int) -> SharedPointer {
return .init(pointer: UnsafeMutablePointer.allocate(capacity: capacity))
}
init(pointer: UnsafeMutablePointer<Pointee>) {
self.ptr = pointer
}
deinit {
ptr.deallocate()
}
}
With that, this becomes (no deinit required):
class Person {
// case1
let pointer1 = SharedPointer<Int>.allocate(capacity: 1)
// case2
let pointer2: SharedPointer<Int>
let name: String
init(name: String) throws {
// case2
self.pointer2 = SharedPointer<Int>.allocate(capacity: 1)
if name == "UnsupportName" {
throw NSError()
}
self.name = name
}
}
You'd probably want to write various helpers for dealing with .ptr.
Of course this might lead you to build specific versions of SharedPointer to deal with each kind of thing (like "father" rather than "int"). If you continue down that road, you'll find the UnsafeMutablePointers evaporate, and the problem goes away. But you don't have to go that far, and SharedPointer will do the work for you.

I found a solution to my problem.
import XCTest
class Person {
// case1
let pointer1: UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>.allocate(capacity: 1)
// case2
let pointer2: UnsafeMutablePointer<Int>
let name: String
init(name: String) throws {
// deallocate helper for case1
var deallocateHelper1: UnsafeMutablePointer<Int>? = self.pointer1
defer {
deallocateHelper1?.deallocate()
}
// case2
self.pointer2 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
var deallocateHelper2: UnsafeMutablePointer<Int>? = self.pointer2
defer {
deallocateHelper2?.deallocate()
}
// case ...
if name == "UnsupportName" {
throw NSError()
}
self.name = name
// In the end. set deallocate helpers to nil
deallocateHelper1 = nil
deallocateHelper2 = nil
}
deinit {
pointer1.deallocate()
pointer2.deallocate()
}
}
class InterestTests: XCTestCase {
func testExample() {
while true {
_ = try? Person(name: "UnsupportName")
}
}
}

Another solution.
class Person {
let name: String
let pointer1: UnsafeMutablePointer<Int>
let pointer2: UnsafeMutablePointer<Int>
init(name: String) throws {
var pointers: [UnsafeMutablePointer<Int>] = []
do {
let pointer1 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
pointers.append(pointer1)
let pointer2 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
pointers.append(pointer2)
if name == "Unsupported Name" {
throw NSError()
}
self.pointer1 = pointer1
self.pointer2 = pointer2
self.name = name
} catch {
pointers.forEach { $0.deallocate() }
throw error
}
}
deinit {
pointer1.deallocate()
pointer2.deallocate()
}
}

Related

singleton property set with async\await func is nil after called later

a property from a singleton is nil when checkin is value.
calling this function from viewDidLoad like this
Task {
do {
try await CXOneChat.shared.connect(environment: .NA1, brandId: 1111, channelId: "keyID")
self.checkForConfig()
} catch {
print(error.localizedDescription)
}
}
this connect function checks for several issues and load from network the config
public func connect(environment: Environment, brandId: Int, channelId: String) async throws {
self.environment = environment
self.brandId = brandId
self.channelId = channelId
try connectToSocket()
channelConfig = try await loadChannelConfiguration()
generateDestinationId()
generateVisitor()
if customer == nil {
customer = Customer(senderId: UUID().uuidString, displayName: "")
try await authorizeCustomer()
} else if authorizationCode.isEmpty{
try await reconnectCustomer()
} else {
try await authorizeCustomer()
}
}
this work ok the self.checkForConfig does some stuff with config in singleton object.
after tapping a button and go for another ViewController. call this func
func loadThread() {
do {
if CXOneChat.shared.getChannelConfiguration()?.settings.hasMultipleThreadsPerEndUser ?? false {
try CXOneChat.shared.loadThreads()
} else {
try CXOneChat.shared.loadThread()
}
} catch {
print(error)
}
}
depending on the config call one or another config value load one or the function. in this case the getChannelConfiguration() is nil and call to loadThread().
func loadThread(threadId: UUID? = nil) throws {
guard let config = channelConfig else {
throw CXOneChatError.missingChannelConfig
}
let eventType = config.isLiveChat ? EventType.recoverLivechat : EventType.recoverThread
guard let brandId = brandId else { throw CXOneChatError.invalidBrandId }
guard let channelId = channelId else { throw CXOneChatError.invalidChannelId }
guard let id = getIdentity(with: false) else { throw CXOneChatError.invalidCustomerId }
let retrieveThread = EventFactory.shared.recoverLivechatThreadEvent(brandId: brandId, channelId: channelId, customer: id, eventType: eventType, threadId: threadId)
guard let data = getDataFrom(retrieveThread) else { throw CXOneChatError.invalidData }
let string = getStringFromData(data)
socketService.send(message: string)
}
here checks for he config in singleton object but throws error because config is nil.
my question is why is nil config in this check. the config is downloaded and store. but when get the values got a null value. Im missing some code here or what I is wrong with this.

What is the main difference between the "return function" and the "callback function"?

I think I am going to change all of my code functions from "callback functions" to "return functions". I don't like the "stairs" look of my code.
Do you think it is a good idea?
I don't understand the difference between the two (except for the asynchronous web service calls that force the use of the callback function in my code).
Callback function:
Declaration:
func methodToSelectData(strQuery : String, dataBase: String, completion: #escaping (_ result: [AnyObject]) -> Void) {
let arryToReturn : [AnyObject] = []
let contactDB = FMDatabase(path: String(methodToCreateDatabase(dataBase: dataBase)!.absoluteString) )
if (contactDB?.open())! {
let results:FMResultSet? = contactDB?.executeQuery(strQuery, withArgumentsIn: nil)
while results?.next() == true {
arryToReturn.add(results!.resultDictionary())
}
if arryToReturn.count == 0 {
completion(arryToReturn)
}
contactDB?.close()
} else {
print("Error: \(String(describing: contactDB?.lastErrorMessage()))")
}
completion(arryToReturn)
}
Usage:
DBHandler.sharedInstance.methodToSelectData(strQuery:"SELECT * FROM table", dataBase: "DB.db", completion: { resultQuery in
if (resultQuery.count > 0) {
...
}
})
Return function
Declaration:
func method2ToSelectData(strQuery : String, dataBase: String) -> [AnyObject] {
let arryToReturn : [AnyObject] = []
let contactDB = FMDatabase(path: String(methodToCreateDatabase(dataBase: dataBase)!.absoluteString) )
if (contactDB?.open())! {
let results:FMResultSet? = contactDB?.executeQuery(strQuery, withArgumentsIn: nil)
while results?.next() == true {
arryToReturn.add(results!.resultDictionary())
}
if arryToReturn.count == 0 {
return arryToReturn
}
contactDB?.close()
} else {
print("Error: \(String(describing: contactDB?.lastErrorMessage()))")
}
return arryToReturn
}
Usage:
let resultQuery = DBHandler.sharedInstance.method2ToSelectData(strQuery:"SELECT * FROM table", dataBase: "DB.db")
if (resultQuery.count > 0) {
...
}
What is the best way to use one or the other? I don't understand the subtlety very well.
It's really a matter of what you need in any given situation.
For something as simple as returning a piece of data, you can do just that:
// Definition //
func newString(firstHalf: String, secondHalf: String) -> String {
return firstHalf + secondHalf
}
// Usage //
print(newString(firstHalf: "Hello", secondHalf: "world"))
Something more complicated, like a data call, might need a completion handler or closure:
// Definition //
func getData(fromEndpoint endpoint: String, completion: (String) -> Void) {
let data = serverData(from: endpoint) //Makes the server request.
completion(data)
}
// Usage //
getData(fromEndpoint: "https://www.reddit.com/.json") { data in
doThings(with: data)
}
You don't necessarily need an asynchronous call to use a closure/callback, but it tends to be one of the most common use-cases for one. As you do more coding in Swift, you'll find more use-cases for each.

How to implement a Thread Safe HashTable (PhoneBook) Data Structure in Swift?

I am trying to implement a Thread-Safe PhoneBook object. The phone book should be able to add a person, and look up a person based on their name and phoneNumber. From an implementation perspective this simply involves two hash tables, one associating name -> Person and another associating phone# -> Person.
The caveat is I want this object to be threadSafe. This means I would like to be able to support concurrent lookups in the PhoneBook while ensuring only one thread can add a Person to the PhoneBook at a time. This is the basic reader-writers problem, and I am trying to solve this using GrandCentralDispatch and dispatch barriers. I am struggling to solve this though as I am running into issues.. Below is my Swift playground code:
//: Playground - noun: a place where people can play
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
public class Person: CustomStringConvertible {
public var description: String {
get {
return "Person: \(name), \(phoneNumber)"
}
}
public var name: String
public var phoneNumber: String
private var readLock = ReaderWriterLock()
public init(name: String, phoneNumber: String) {
self.name = name
self.phoneNumber = phoneNumber
}
public func uniquePerson() -> Person {
let randomID = UUID().uuidString
return Person(name: randomID, phoneNumber: randomID)
}
}
public enum Qos {
case threadSafe, none
}
public class PhoneBook {
private var qualityOfService: Qos = .none
public var nameToPersonMap = [String: Person]()
public var phoneNumberToPersonMap = [String: Person]()
private var readWriteLock = ReaderWriterLock()
public init(_ qos: Qos) {
self.qualityOfService = qos
}
public func personByName(_ name: String) -> Person? {
var person: Person? = nil
if qualityOfService == .threadSafe {
readWriteLock.concurrentlyRead { [weak self] in
guard let strongSelf = self else { return }
person = strongSelf.nameToPersonMap[name]
}
} else {
person = nameToPersonMap[name]
}
return person
}
public func personByPhoneNumber( _ phoneNumber: String) -> Person? {
var person: Person? = nil
if qualityOfService == .threadSafe {
readWriteLock.concurrentlyRead { [weak self] in
guard let strongSelf = self else { return }
person = strongSelf.phoneNumberToPersonMap[phoneNumber]
}
} else {
person = phoneNumberToPersonMap[phoneNumber]
}
return person
}
public func addPerson(_ person: Person) {
if qualityOfService == .threadSafe {
readWriteLock.exclusivelyWrite { [weak self] in
guard let strongSelf = self else { return }
strongSelf.nameToPersonMap[person.name] = person
strongSelf.phoneNumberToPersonMap[person.phoneNumber] = person
}
} else {
nameToPersonMap[person.name] = person
phoneNumberToPersonMap[person.phoneNumber] = person
}
}
}
// A ReaderWriterLock implemented using GCD and OS Barriers.
public class ReaderWriterLock {
private let concurrentQueue = DispatchQueue(label: "com.ReaderWriterLock.Queue", attributes: DispatchQueue.Attributes.concurrent)
private var writeClosure: (() -> Void)!
public func concurrentlyRead(_ readClosure: (() -> Void)) {
concurrentQueue.sync {
readClosure()
}
}
public func exclusivelyWrite(_ writeClosure: #escaping (() -> Void)) {
self.writeClosure = writeClosure
concurrentQueue.async(flags: .barrier) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.writeClosure()
}
}
}
// MARK: Testing the synchronization and thread-safety
for _ in 0..<5 {
let iterations = 1000
let phoneBook = PhoneBook(.none)
let concurrentTestQueue = DispatchQueue(label: "com.PhoneBookTest.Queue", attributes: DispatchQueue.Attributes.concurrent)
for _ in 0..<iterations {
let person = Person(name: "", phoneNumber: "").uniquePerson()
concurrentTestQueue.async {
phoneBook.addPerson(person)
}
}
sleep(10)
print(phoneBook.nameToPersonMap.count)
}
To test my code I run 1000 concurrent threads that simply add a new Person to the PhoneBook. Each Person is unique so after the 1000 threads complete I am expecting the PhoneBook to contain a count of 1000. Everytime I perform a write I perform a dispatch_barrier call, update the hash tables, and return. To my knowledge this is all we need to do; however, after repeated runs of the 1000 threads I get the number of entries in the PhoneBook to be inconsistent and all over the place:
Phone Book Entries: 856
Phone Book Entries: 901
Phone Book Entries: 876
Phone Book Entries: 902
Phone Book Entries: 912
Can anyone please help me figure out what is going on? Is there something wrong with my locking code or even worse something wrong with how my test is constructed? I am very new to this multi-threaded problem space, thanks!
The problem is your ReaderWriterLock. You are saving the writeClosure as a property, and then asynchronously dispatching a closure that calls that saved property. But if another exclusiveWrite came in during the intervening period of time, your writeClosure property would be replaced with the new closure.
In this case, it means that you can be adding the same Person multiple times. And because you're using a dictionary, those duplicates have the same key, and therefore don't result in you're seeing all 1000 entries.
You can actually simplify ReaderWriterLock, completely eliminating that property. I’d also make concurrentRead a generic, returning the value (just like sync does), and rethrowing any errors (if any).
public class ReaderWriterLock {
private let queue = DispatchQueue(label: "com.domain.app.rwLock", attributes: .concurrent)
public func concurrentlyRead<T>(_ block: (() throws -> T)) rethrows -> T {
return try queue.sync {
try block()
}
}
public func exclusivelyWrite(_ block: #escaping (() -> Void)) {
queue.async(flags: .barrier) {
block()
}
}
}
A couple of other, unrelated observations:
By the way, this simplified ReaderWriterLock happens to solves another concern. That writeClosure property, which we've now removed, could have easily introduced a strong reference cycle.
Yes, you were scrupulous about using [weak self], so there wasn't any strong reference cycle, but it was possible. I would advise that wherever you employ a closure property, that you set that closure property to nil when you're done with it, so any strong references that closure may have accidentally entailed will be resolved. That way a persistent strong reference cycle is never possible. (Plus, the closure itself and any local variables or other external references it has will be resolved.)
You're sleeping for 10 seconds. That should be more than enough, but I'd advise against just adding random sleep calls (because you never can be 100% sure). Fortunately, you have a concurrent queue, so you can use that:
concurrentTestQueue.async(flags: .barrier) {
print(phoneBook.count)
}
Because of that barrier, it will wait until everything else you put on that queue is done.
Note, I did not just print nameToPersonMap.count. This array has been carefully synchronized within PhoneBook, so you can't just let random, external classes access it directly without synchronization.
Whenever you have some property which you're synchronizing internally, it should be private and then create a thread-safe function/variable to retrieve whatever you need:
public class PhoneBook {
private var nameToPersonMap = [String: Person]()
private var phoneNumberToPersonMap = [String: Person]()
...
var count: Int {
return readWriteLock.concurrentlyRead {
nameToPersonMap.count
}
}
}
You say you're testing thread safety, but then created PhoneBook with .none option (achieving no thread-safety). In that scenario, I'd expect problems. You have to create your PhoneBook with the .threadSafe option.
You have a number of strongSelf patterns. That's rather unswifty. It is generally not needed in Swift as you can use [weak self] and then just do optional chaining.
Pulling all of this together, here is my final playground:
PlaygroundPage.current.needsIndefiniteExecution = true
public class Person {
public let name: String
public let phoneNumber: String
public init(name: String, phoneNumber: String) {
self.name = name
self.phoneNumber = phoneNumber
}
public static func uniquePerson() -> Person {
let randomID = UUID().uuidString
return Person(name: randomID, phoneNumber: randomID)
}
}
extension Person: CustomStringConvertible {
public var description: String {
return "Person: \(name), \(phoneNumber)"
}
}
public enum ThreadSafety { // Changed the name from Qos, because this has nothing to do with quality of service, but is just a question of thread safety
case threadSafe, none
}
public class PhoneBook {
private var threadSafety: ThreadSafety
private var nameToPersonMap = [String: Person]() // if you're synchronizing these, you really shouldn't expose them to the public
private var phoneNumberToPersonMap = [String: Person]() // if you're synchronizing these, you really shouldn't expose them to the public
private var readWriteLock = ReaderWriterLock()
public init(_ threadSafety: ThreadSafety) {
self.threadSafety = threadSafety
}
public func personByName(_ name: String) -> Person? {
if threadSafety == .threadSafe {
return readWriteLock.concurrentlyRead { [weak self] in
self?.nameToPersonMap[name]
}
} else {
return nameToPersonMap[name]
}
}
public func personByPhoneNumber(_ phoneNumber: String) -> Person? {
if threadSafety == .threadSafe {
return readWriteLock.concurrentlyRead { [weak self] in
self?.phoneNumberToPersonMap[phoneNumber]
}
} else {
return phoneNumberToPersonMap[phoneNumber]
}
}
public func addPerson(_ person: Person) {
if threadSafety == .threadSafe {
readWriteLock.exclusivelyWrite { [weak self] in
self?.nameToPersonMap[person.name] = person
self?.phoneNumberToPersonMap[person.phoneNumber] = person
}
} else {
nameToPersonMap[person.name] = person
phoneNumberToPersonMap[person.phoneNumber] = person
}
}
var count: Int {
return readWriteLock.concurrentlyRead {
nameToPersonMap.count
}
}
}
// A ReaderWriterLock implemented using GCD concurrent queue and barriers.
public class ReaderWriterLock {
private let queue = DispatchQueue(label: "com.domain.app.rwLock", attributes: .concurrent)
public func concurrentlyRead<T>(_ block: (() throws -> T)) rethrows -> T {
return try queue.sync {
try block()
}
}
public func exclusivelyWrite(_ block: #escaping (() -> Void)) {
queue.async(flags: .barrier) {
block()
}
}
}
for _ in 0 ..< 5 {
let iterations = 1000
let phoneBook = PhoneBook(.threadSafe)
let concurrentTestQueue = DispatchQueue(label: "com.PhoneBookTest.Queue", attributes: .concurrent)
for _ in 0..<iterations {
let person = Person.uniquePerson()
concurrentTestQueue.async {
phoneBook.addPerson(person)
}
}
concurrentTestQueue.async(flags: .barrier) {
print(phoneBook.count)
}
}
Personally, I'd be inclined to take it a step further and
move the synchronization into a generic class; and
change the model to be an array of Person object, so that:
The model supports multiple people with the same or phone number; and
You can use value types if you want.
For example:
public struct Person {
public let name: String
public let phoneNumber: String
public static func uniquePerson() -> Person {
return Person(name: UUID().uuidString, phoneNumber: UUID().uuidString)
}
}
public struct PhoneBook {
private var synchronizedPeople = Synchronized([Person]())
public func people(name: String? = nil, phone: String? = nil) -> [Person]? {
return synchronizedPeople.value.filter {
(name == nil || $0.name == name) && (phone == nil || $0.phoneNumber == phone)
}
}
public func append(_ person: Person) {
synchronizedPeople.writer { people in
people.append(person)
}
}
public var count: Int {
return synchronizedPeople.reader { $0.count }
}
}
/// A structure to provide thread-safe access to some underlying object using reader-writer pattern.
public class Synchronized<T> {
/// Private value. Use `public` `value` computed property (or `reader` and `writer` methods)
/// for safe, thread-safe access to this underlying value.
private var _value: T
/// Private reader-write synchronization queue
private let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".synchronized", qos: .default, attributes: .concurrent)
/// Create `Synchronized` object
///
/// - Parameter value: The initial value to be synchronized.
public init(_ value: T) {
_value = value
}
/// A threadsafe variable to set and get the underlying object, as a convenience when higher level synchronization is not needed
public var value: T {
get { reader { $0 } }
set { writer { $0 = newValue } }
}
/// A "reader" method to allow thread-safe, read-only concurrent access to the underlying object.
///
/// - Warning: If the underlying object is a reference type, you are responsible for making sure you
/// do not mutating anything. If you stick with value types (`struct` or primitive types),
/// this will be enforced for you.
public func reader<U>(_ block: (T) throws -> U) rethrows -> U {
return try queue.sync { try block(_value) }
}
/// A "writer" method to allow thread-safe write with barrier to the underlying object
func writer(_ block: #escaping (inout T) -> Void) {
queue.async(flags: .barrier) {
block(&self._value)
}
}
}
In some cases you use might NSCache class. The documentation claims that it's thread safe:
You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.
Here is an article that describes quite useful tricks related to NSCache
I don’t think you are using it wrong :).
The original (on macos) generates:
0 swift 0x000000010c9c536a PrintStackTraceSignalHandler(void*) + 42
1 swift 0x000000010c9c47a6 SignalHandler(int) + 662
2 libsystem_platform.dylib 0x00007fffbbdadb3a _sigtramp + 26
3 libsystem_platform.dylib 000000000000000000 _sigtramp + 1143284960
4 libswiftCore.dylib 0x0000000112696944 _T0SSwcp + 36
5 libswiftCore.dylib 0x000000011245fa92 _T0s24_VariantDictionaryBufferO018ensureUniqueNativeC0Sb11reallocated_Sb15capacityChangedtSiF + 1634
6 libswiftCore.dylib 0x0000000112461fd2 _T0s24_VariantDictionaryBufferO17nativeUpdateValueq_Sgq__x6forKeytF + 1074
If you remove the ‘.concurrent’ from your ReaderWriter queue, "the problem disappears”.©
If you restore the .concurrent, but change the async invocation in the writer side to be sync:
swift(10504,0x70000896f000) malloc: *** error for object 0x7fcaa440cee8: incorrect checksum for freed object - object was probably modified after being freed.
Which would be a bit astonishing if it weren’t swift?
I dug in, replaced your ‘string’ based array with an Int one by interposing a hash function, replaced the sleep(10) with a barrier dispatch to flush any laggardly blocks through, and that made it more reproducibly crash with the somewhat more helpful:
x(10534,0x700000f01000) malloc: *** error for object 0x7f8c9ee00008: incorrect checksum for freed object - object was probably modified after being freed.
But when a search of the source revealed no malloc or free, perhaps the stack dump is more useful.
Anyways, best way to solve your problem: use go instead; it actually makes sense.

get the type/class of a property from its name in swift

Lets say I have this class:
class Node {
var value: String
var children: [Node]?
}
If I have the name of one of its properties (for example "children") how can I get its type? (In this case [Node]?)
I imagine having a global function like below will solve my needs:
func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
//???
}
// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)
Swift 2 (Note: Reflection changed):
import Foundation
enum PropertyTypes:String
{
case OptionalInt = "Optional<Int>"
case Int = "Int"
case OptionalString = "Optional<String>"
case String = "String"
//...
}
extension NSObject{
//returns the property type
func getTypeOfProperty(name:String)->String?
{
let type: Mirror = Mirror(reflecting:self)
for child in type.children {
if child.label! == name
{
return String(child.value.dynamicType)
}
}
return nil
}
//Property Type Comparison
func propertyIsOfType(propertyName:String, type:PropertyTypes)->Bool
{
if getTypeOfProperty(propertyName) == type.rawValue
{
return true
}
return false
}
}
custom class:
class Person : NSObject {
var id:Int?
var name : String?
var email : String?
var password : String?
var child:Person?
}
get the type of the "child" property:
let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>
property type checking:
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true
or
if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
//true -> do something
}
else
{
//false -> do something
}
Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
subscript(i: Int) -> (String, MirrorType) { get }
This seems to work:
func getTypeOfVariableWithName(name: String, inInstance instance: Any) -> String? {
let mirror = reflect(instance)
var variableCollection = [String: MirrorType]()
for item in 0..<mirror.count {
variableCollection[mirror[item].0] = mirror[item].1
}
if let type = variableCollection[name] {
let longName = _stdlib_getDemangledTypeName(type.value)
let shortName = split(longName, { $0 == "."}).last
return shortName ?? longName
}
return nil
}
Here's some example code on SwiftStub.
Edit:
The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".
I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.
Building on #PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:
extension NSObject {
// Returns the property type
func getTypeOfProperty (name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
while let parent = type.superclassMirror() {
for child in parent.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
type = parent
}
return nil
}
}
Hope this may help someone.
Swift 3 update:
// Extends NSObject to add a function which returns property type
extension NSObject {
// Returns the property type
func getTypeOfProperty (_ name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
type = parent
}
return nil
}
}
The solution provided by #peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}

Closure : Use unresolved identifier 'self'

I'm parsing the Swift Language Guide tutorial (from Apple iOS dev library) and for every chapter I create a separate swift file.
In each file I create multiple functions where I isolate snippets of code that they provide. Everything worked on until testing the Strong Reference Cycles for Closures.
For some reason if the class that contains a closure (for a computed property) is declared inside a function, then the closure cannot see the "self" reference of the enclosing class. Any ideas why ?
It works fine if the class is not declared inside a function.
func strongRefClosure() {
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML())
}
Looks very much like a bug (or at least, a behaviour of function-local structs/classes I can’t find documented). This works fine:
struct Foo {
let someVal = 5
lazy var someLazy: String = {
return toString(self.someVal)
}()
}
var foo = Foo()
foo.someLazy // string "5"
But this doesn’t:
func outer() {
struct Foo {
let someVal = 5
lazy var someLazy: String = {
// error: use of unresolved identifier 'self'
return toString(self.someVal)
}()
}
var foo = Foo()
foo.someLazy
}
An inner struct inside an outer struct works, though:
struct Outer {
struct Foo {
let someVal = 5
lazy var someLazy: String = {
return toString(self.someVal)
}()
}
var foo = Foo()
}
var outer = Outer()
outer.foo.someLazy
As #JeremyP says, you should file a radar.
For me, I have this bug in XCode 8GM, Swift 3, iOS 10.0.
tl;dr
Closure-as-instance-property has bug
Closure-as-computed-property is cured!
Actual code
Buggy:
let permissionStatusHandler = { (status: CKApplicationPermissionStatus, error: Error?) in
switch status {
case .granted:
self.fetchUserRecordID() // Buggy: Use of unresolved identifier 'self'
case .initialState:
self.requestDiscoverability() // Buggy: Use of unresolved identifier 'self'
case .couldNotComplete:
error.then { print(#function, $0.localizedDescription) }
fallthrough
case .denied:
self.iCloud.presentiCloudAlert(for: status)
}
}
Kosher:
var permissionStatusHandler: (CKApplicationPermissionStatus, Error?) -> () { return
{ (status: CKApplicationPermissionStatus, error: Error?) in
switch status {
case .granted:
self.fetchUserRecordID()
case .initialState:
self.requestDiscoverability()
case .couldNotComplete:
error.then { print(#function, $0.localizedDescription) }
fallthrough
case .denied:
self.iCloud.presentiCloudAlert(for: status)
}
}
}
Hope this helps some other soul out there.