"private lazy var ..." thread safe?

Just had a weird crash in development in Simulator - first of a kind. The crash was on this line:


private lazy var regExTrimSet = NSCharacterSet(charactersInString: " \t\r\n_")


and the error was some malloc() already released (grrr, should have copied it). Should that be thread safe? [Its being referenced by a bunch of concurrent blocks at one point]


Also, I tried to find out where the Xcode console log might get written, but had no luck finding a link. Is there one that this error should be logged to?

Accepted Reply

Some notes added to clarify this situation in the recent Swift book.


In the Lazy Stored Property part of Stored Properties:

If a property marked with the

lazy
modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.


In the Type Properties section:

Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the

lazy
modifier.


It seems not all `lazy` variables are guaranteed to be initialized once in multi-threaded environment. You need to explicitly program it so or use static property.


And as already noted, all Cocoa/Cocoa Touch classes and methods are not thread-safe, except ones explicitly declared as thread-safe in the documentations. Immutable classes are strongly expected to be thread-safe, but it is not guaranteed.

Replies

Cocoa is *NOT* thread safe.

Some notes added to clarify this situation in the recent Swift book.


In the Lazy Stored Property part of Stored Properties:

If a property marked with the

lazy
modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.


In the Type Properties section:

Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the

lazy
modifier.


It seems not all `lazy` variables are guaranteed to be initialized once in multi-threaded environment. You need to explicitly program it so or use static property.


And as already noted, all Cocoa/Cocoa Touch classes and methods are not thread-safe, except ones explicitly declared as thread-safe in the documentations. Immutable classes are strongly expected to be thread-safe, but it is not guaranteed.

NSCharacterSet is Foundation, not Cocoa. From the "Thread Programming Guide":


Guidelines for using Cocoa from multiple threads include the following:

...

Immutable objects are generally thread-safe. Once you create them, you can safely pass these objects to and from threads. On the other hand, mutable objects are generally not thread-safe.

I found a list of classes that are "generally considered to be thread-safe".

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html

The following classes and functions are generally considered to be thread-safe. You can use the same instance from multiple threads without first acquiring a lock. 

NSArray
NSAssertionHandler
NSAttributedString
NSBundle
NSCalendar
NSCalendarDate
NSCharacterSet
NSConditionLock
NSConnection
NSData
NSDate
NSDateFormatter
NSDecimal functions
NSDecimalNumber
NSDecimalNumberHandler
NSDeserializer
NSDictionary
NSDistantObject
NSDistributedLock
NSDistributedNotificationCenter
NSException
NSFileManager
NSFormatter
NSHost
NSJSONSerialization
NSLock
NSLog/NSLogv
NSMethodSignature
NSNotification
NSNotificationCenter
NSNumber
NSNumberFormatter
NSObject
NSOrderedSet
NSPortCoder
NSPortMessage
NSPortNameServer
NSProgress
NSProtocolChecker
NSProxy
NSRecursiveLock
NSSet
NSString
NSThread
NSTimer
NSTimeZone
NSUserDefaults
NSValue
NSXMLParser
Object allocation and retain count functions
Zone and memory functions



Are you sure, you need lazy var for it? There is no heavy calculation and self using. Why you don't use let?

private lazy var regExTrimSet = NSCharacterSet(charactersInString: " \t\r\n_")

Or just do it NSCharacterSet static property via extension.

I wrote this 6 years ago! I don't know if this was a static property or an ivar. I just did a search on my compute, I can't find a reference to "regExTrimSet" so that code is either archived or deleted. Guessing I just removed the lazy but unsure at this point.