Singleton Class and multiple asynchronous operations in Swift - ios

I am writing an iOS Swift application that, upon startup, needs to get 2 (or more) sets of data from a server. During initialization, I must do some processing on the sets of data - kind of merging them together. And only then can I start my view controller and interact with the user. The data obtained during initialization is an array of objects that I reuse everywhere in my app.
At first, I put the code in the viewDidLoad of the view controller, but it became messy very quickly. Now, I am putting all this code inside a "singleton" class so that all my view controllers can reuse the same data. My singleton class is defined using the following code excerpt:
class Teams {
var teams: [Team]
static var sharedInstance = Teams()
private init() {
teams = []
let queryText = "CardTypeOWSTEXT:Root"
//The first async call (DataManager invokes the http REST to the server)
DataManager.spSearch (queryText, success: { teamsJson -> Void in
let json = JSON(data: teamsJson)
...
// all the code to handle the data received from the server
...
})
//The second async call
DataManager.spSocialFollowedSites ({ sitesJson -> Void in
let json = JSON(data: sitesJson)
...
// all the code to handle the data received from the server
...
})
I am very new to iOS development, and I try to replicate an existing app I wrote in AngularJS. In that app, it is very simple to invoke the REST calls to the server and using promises, all I have to do is wait for both to complete to execute the matching with a statement like:
$q.all([promise1, promise2]).then(...)
but this is javascript/angular, not Swift! I know there are promises libraries (eg. PromiseKit), but I am wondering if this is the right way to do it? Would it be simpler/better with GCD? Also, does my approach using a singleton makes sense? Its purpose is to hold data shared by all the other classes, and in angular, the same concept is a factory and works quite well...
I have read many places and could not get any good guidance, so any help would be appreciated!

I use PromiseKit in my code and I'm very satisfied, that said - you can always synchronise without it. It's called a semaphore. Basically:
Set a counter to 2.
when a function is done - decrement it by one and save the value.
When it hits zero, call a function.
Basically, something like:
var counter = 2
var firstResult: teamsJsonType?
var secondResult: sitesJsonType?
let handler = ... ; // function code that runs when both results are ready
DataManager.spSearch (queryText, success: { teamsJson -> Void in
firstResult = teamsJson
counter -= 1
if counter == 0 { handler() }
})
DataManager.spSocialFollowedSites ({ sitesJson -> Void in
secondResult = sitesJson
counter -= 1
if counter == 0 { handler() }
})

Related

What is the reason behind objc_sync_enter doesn't work well with struct, but works well with class?

I have the following demo code.
struct IdGenerator {
private var lastId: Int64
private var set: Set<Int64> = []
init() {
self.lastId = 0
}
mutating func nextId() -> Int64 {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
repeat {
lastId = lastId + 1
} while set.contains(lastId)
precondition(lastId > 0)
let (inserted, _) = set.insert(lastId)
precondition(inserted)
return lastId
}
}
var idGenerator = IdGenerator()
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func click(_ sender: Any) {
DispatchQueue.global(qos: .userInitiated).async {
for i in 1...10000 {
let id = idGenerator.nextId()
print("i : \(id)")
}
}
DispatchQueue.global(qos: .userInitiated).async {
for j in 1...10000 {
let id = idGenerator.nextId()
print("j : \(id)")
}
}
}
}
Whenever I execute click, I would get the following crash
Thread 5 Queue : com.apple.root.user-initiated-qos (concurrent)
#0 0x000000018f58b434 in _NativeSet.insertNew(_:at:isUnique:) ()
#1 0x000000018f598d10 in Set._Variant.insert(_:) ()
#2 0x00000001001fe31c in IdGenerator.nextId() at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:30
#3 0x00000001001fed8c in closure #2 in ViewController.click(_:) at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:56
It isn't clear why the crash happen. My raw guess is, under struct, objc_sync_enter(self) doesn't work as expected. 2 threads accessing Set simultaneously will cause such an issue.
If I change the struct to class, everything just work fine.
class IdGenerator {
private var lastId: Int64
private var set: Set<Int64> = []
init() {
self.lastId = 0
}
func nextId() -> Int64 {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
repeat {
lastId = lastId + 1
} while set.contains(lastId)
precondition(lastId > 0)
let (inserted, _) = set.insert(lastId)
precondition(inserted)
return lastId
}
}
May I know what is the reason behind? Why the above objc_sync_enter works well in class, but not in struct?
The objc_sync_enter/objc_sync_exit functions take an object instance and use its identity (i.e., address in memory) in order to allocate and associate a lock in memory — and use that lock to protect the code between the enter and exit calls.
However, structs are not objects, and don't have reference semantics which would allow them to be used in this way — they're not even guaranteed to be allocated in a stable location in memory. However, to support interoperation with Objective-C, structs must have a consistent object-like representation when used from Objective-C, or else calling Objective-C code with, say, a struct inside of an Any instance could trigger undefined behavior.
When a struct is passed to Objective-C in the guise of an object (e.g., inside of Any, or AnyObject), it is wrapped up in a temporary object of a private class type called __SwiftValue. This allows it to look like an object to Objective-C, and in some cases, be used like an object, but critically, it is not a long-lived, stable object.
You can see this with the following code:
struct Foo {}
let f = Foo()
print(f) // => Foo()
print(f as AnyObject) // => __SwiftValue
print(ObjectIdentifier(f as AnyObject)) // => ObjectIdentifier(0x0000600002595900)
print(ObjectIdentifier(f as AnyObject)) // => ObjectIdentifier(0x0000600002595c60)
The pointers will change run to run, but you can see that every time f is accessed as an AnyObject, it will have a new address.
This means that when you call objc_sync_enter on a struct, a new __SwiftValue object will be created to wrap your struct, and that object is passed in to objc_sync_enter. objc_sync_enter will then associate a new lock with the temporary object value which was automatically created for you... and then that object is immediately deallocated. This means two major things:
When you call objc_sync_exit, a new object will be created and passed in, but the runtime has no lock associated with that new object instance! It may crash at this point.
Every time you call objc_sync_enter, you're creating a new, separate lock... which means that there's effectively no synchronization at all: every thread is getting a new lock altogether.
This new pointer instance isn't guaranteed — depending on optimization, the object may live long enough to be reused across objc_sync_* calls, or a new object could be allocated exactly in the same place as an old one... or a new object could be allocated where a different struct used to be, and you accidentally unlock a different thread...
All of this means that you should definitely avoid using objc_sync_enter/objc_sync_exit as a locking mechanism from Swift, and switch over to something like NSLock, an allocated os_unfair_lock, or even a DispatchQueue, which are well-supported from Swift. (Really, the objc_sync_* functions are primitives for use largely by the Obj-C runtime only, and probably should be un-exposed to Swift.)

Memory Leak Kotlin Native library in iOS

I'm building a Kotlin library to use in my iOS app using Kotlin/Native. After I call some methods in the library from Swift, which works, I also want to call methods in Swift from the library. To accomplish this I implemented an interface in the library:
class Outbound {
interface HostInterfaceForTracking {
fun calcFeatureVector(bitmap: Any?): Array<Array<FloatArray>>?
}
var hostInterface: HostInterfaceForTracking? = null
fun registerInterface(hostInterface: HostInterfaceForTracking) {
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
}
}
This is implemented on the Swift side like this:
class HostInterfaceForTracking : OutboundHostInterfaceForTracking {
var t : Outbound? = nil
init() {
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
func calcFeatureVector(bitmap: Any?) -> KotlinArray<KotlinArray<KotlinFloatArray>>? {
do {
var test : Any? = (bitmap as! Bitmap).bitmap
return nil
} catch {
return nil
}
}
}
The TrackingWrapper looks like this:
class TrackingWrapper : NSObject {
static var instance: TrackingWrapper? = nil
var inbound: Inbound? = nil
var worker: Worker
override init() {
self.worker = Worker()
super.init()
initInboundInterface()
}
func initInboundInterface() {
runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
HostInterfaceForTracking()
}
}
func runOnMatchingLibraryThread(block: #escaping() -> Void) {
worker.enqueue {
block()
}
}
}
The function runOnMatchingLibraryThread is needed because every call to the TrackingLibrary needs to be called from the exact same thread, so the Worker class initializes a thread and enqueues every method to that thread.
The Bitmap in this case is simply a wrapper for an UIImage, which I already accessed with the .bitmap call, so I've tried to access the wrapped UIImage and save it in the test variable. The library gets the current camera frame from the Swift side every few frames and sends the current image wrapped as a Bitmap to the method calcFeatureVector depicted here.
Problem: My memory load starts increasing as soon as the app starts until the point it crashes. This is not the case if I don't access the wrapped UIImage (var test : Any? = (bitmap as! Bitmap)). So there is a huge memory leak, just by accessing the wrapped variable on the Swift side. Is there anything I've missed or is there any way to release the memory?
Looks like you have a circular dependency here:
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
You are asking a property inside HostInterfaceForTracking to maintain a strong reference to the same instance of HostInterfaceForTracking. You should be using [weak self] to avoid the circular reference.
EDIT:
Ok after seeing the rest of you code theres a lot to unpack. There is a lot of unnecessary bouncing back and forth between classes, functions and threads.
There is no need to use runOnMatchingLibraryThread to just create an instance of something. You only need to use that for the code processing the image itself (I would assume, I haven't seen anything so far that requires being split off into another thread). Inside TrackingWrapper, you can create a singleton more easily, and matching the swift pattern by simply doing this as the first line:
static let shared = TrackingWrapper()
And everywhere you want to use it, you can just call TrackingWrapper.shared. This is more common and will avoid one of the levels of indirection in the code.
I'm not sure what Worker or Inbound are, but again these can and should be created inside the TrackingWrapper init, rather than branching Inbound's init, to use another thread.
Inside initInboundInterface you are creating an instance of HostInterfaceForTracking() which doesn't get stored anywhere. The only reason HostInterfaceForTracking is continuing to stay in memory after its creation, is because of the internal circular dependency inside it. This is 100% causing some form of a memory issue for you. This should probably also be a property on TrackingWrapper, and again, its Init should not be called inside runOnMatchingLibraryThread.
Having HostInterfaceForTracking's init, also using runOnMatchingLibraryThread is problematic. If we inline all the code whats happening is this:
TrackingWrapper
init() {
self.runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
}
Having all these classes unnecessarily keep coming back to TrackingWrapper is going to cause issues.
Inside HostInterfaceForTracking 's init, no need to be creating Outbound on a separate thread. First line in this class can simply be:
var t : Outbound = OutBound()
Or do it in the init if you prefer. Either way will also remove the issue of needing to unwrap Outbound before using it.
Inside Outbound you are storing 2 references to the hostInterface instance:
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
I would have imagined there should only be 1. If there are now multiple copies of a class that has a circular dependency, which has multiple calls to separate threads. This again will cause issues.
I'm still not sure on the differences between Swift and Kotlin. In Swift when passing self into a function to be stored, the class storing it would mark the property as weak, like so:
weak var hostInterface: ......
Which will avoid any circular dependency from forming. A quick google says this isn't how things work in Kotlin. It might be better to look into the swift side passing in a closure (lambda on kotlin) and the kotlin side executing that. This might avoid the need to store a strong reference. Otherwise you need to be looking into some part of your code setting hostInterface back to null. Again its a bit hard to say only seeing some of the code and not knowing how its working.
In short, it looks like the code is very over complicated, and needs to be simplified, so that all these moving pieces can be tracked easier.

Capturing closure values in Swift

My question is very similar to several others here but I just can't get it to work. I'm making an API call via a helper class that I wrote.
First I tried a standard function with a return value and the result was as expected. The background task completed after I tired to assign the result.
Now I'm using a closure and I can get the value back into my view controller but its still stuck in the closure, I have the same problem. I know I need to use GCD to get the assignment to happen in the main queue.
this is what I have in my view controller
var artists = [String]()
let api = APIController()
api.getArtistList("foo fighters") { (thelist) -> Void in
if let names = thelist {
dispatch_async(dispatch_get_main_queue()) {
artists = names
print("in the closure: \(artists)")
}
}
}
print ("method 1 results: \(artists)")
as the results are:
method 1 results: []
in the closure: [Foo Fighters & Brian May, UK Foo Fighters, John Fogerty with Foo Fighters, Foo Fighters, Foo Fighters feat. Norah Jones, Foo Fighters feat. Brian May, Foo Fighters vs. Beastie Boys]
I know why this is happening, I just don't know how to fix it :( The API calls need to be async, so what is the best practice for capturing these results? Based on what the user selects in the table view I'll be making subsequent api calls so its not like I can handle everything inside the closure
I completely agree with the #Craig proposal of the use of the GCD, but as your question involves the request of the API call every time you select a row, you can do the following:
Let's suppose you use the tableView:didSelectRowAtIndexPath: method to handle the selection, then you can do the following inside it:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// it is just a form to get the item
let selectedItem = items.objectAtIndex(indexPath.row) as String
api.getArtistList(selectedItem) { (thelist) -> Void in
if let names = thelist {
dispatch_async(dispatch_get_main_queue()) {
artists = names
}
}
}
}
And then you can observe the property and handle do you want inside it :
var artists: [String] = [] {
didSet {
self.tableView.reloadData() // or anything you need to handle.
}
}
It just another way to see it. I hope this help you.
The easy solution is to do whatever you're doing at your print(), inside the closure.
Since you're already dispatch_asyncing to the main queue (the main/GUI thread), you can complete any processing there. Push a new view controller, present some modal data, update your current view controller, etc.
Just make sure that you don't have multiple threads modifying/accessing your local/cached data that is being displayed. Especially if it's being used by UITableViewDelegate / UITableViewDataSource implementations, which will throw fits if you start getting wishy-washy or inconsistent with your return values.
As long as you can retrieve the data in the background, and the only processing that needs to occur on the main thread is an instance variable reassignment, or some kind of array appending, just do that on the main thread, using the data you retrieved on the back end. It's not heavy. If it is heavy, then you're going to need more sophisticated synchronization methods to protect your data.
Normally the pattern looks like:
dispatch_async(getBackgroundQueue(), {
var theData = getTheDataFromNetwork();
dispatch_async(dispatch_get_main_queue() {
self.data = theData // Update the instance variable of your ViewController
self.tableView.reloadData() // Or some other 'reload' method
});
})
So where you'd normally refresh a table view or notify your ViewController that the operation has completed (or that local data has been updated), you should continue your main-thread processing.

problems using Grand Central Dispatch IOS Swift Xcode 6.3.1

I'm learning swift now and having hard time understanding the multithreading issues..
specific problem Im having is that i'm loading data from the internet and
trying to return an array ("broadcasts") containing this data while using dispatch_async .
My problem is that the return execution with the empty array happens before
the array is filled with the data (this line "println(broadcasts)" happens but the array returns empty.. )
Here is my code:
import UIKit
public class BroadcastRequest {
func requestNewBroadcasts() -> [BroadcastModel] {
var broadcasts = [BroadcastModel]()
var sectionsOfBroadcasts = [[BroadcastModel]]()
DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json = JSON(data: youTubeData)
if let broadcastsArray = json["result"].array {
for broadcastDict in broadcastsArray{
var broadcastID: String? = broadcastDict["id"].string
var broadcastURL: String? = broadcastDict["broadcast"].string
DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json2 = JSON(data: youTubeData)
if let broadcastDetailsDict = json2["result"].dictionary {
var cover: String! = broadcastDetailsDict["cover"]!.string
var caption: String! = broadcastDetailsDict["caption"]!.string
var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
broadcasts.append(broadcast)
**println(broadcasts)**
}
}
}
}
}
}
}
**return broadcasts**
}
}
After looking at answers i have changed the code to this:
import UIKit
public class BroadcastRequest {
func requestNewBroadcasts() {
var broadcasts = [BroadcastModel]()
var sectionsOfBroadcasts = [[BroadcastModel]]()
DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json = JSON(data: youTubeData)
if let broadcastsArray = json["result"].array {
for broadcastDict in broadcastsArray{
var broadcastID: String? = broadcastDict["id"].string
var broadcastURL: String? = broadcastDict["broadcast"].string
DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json2 = JSON(data: youTubeData)
if let broadcastDetailsDict = json2["result"].dictionary {
var cover: String! = broadcastDetailsDict["cover"]!.string
var caption: String! = broadcastDetailsDict["caption"]!.string
var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
broadcasts.append(broadcast)
println(broadcasts)
}
}
}
}
}
}
}
**TableViewController.requestFinished(broadcasts)**
}
}
And in class TableViewController-
public class TableViewController: UITableViewController {
...
...
public func requestFinished(requestedBroadcasts: [BroadcastModel]) {
self.broadcasts = requestedBroadcasts
self.tableView.reloadData()
}
Now i get the error:
Cannot invoke 'requestFinished' with an argument list of type '([(BroadcastModel)])'
Your code is wrong. A call to a GCD function like dispatch_async returns immediately, before the code in the closure has even begun executing. That's the nature of concurrent programming.
You can't write async code that makes a call and then has the answer on the next line. Instead you need to change your logic so that you make the call to dispatch async and then return and forget about the request until the block completes. Then you put the code that handles the result inside the closure. You can add a call inside your closure that calls out to your app on the main thread to notify it that processing is complete.
EDIT:
Your new code has multiple problems:
Your call to dispatch_async is using the main queue, which is a queue on the main thread. If your goal is to get this code to run in the background, this code fails to do that.
The call to TableViewController.requestFinished(broadcasts) is still in the wrong place. It needs to be inside the block, after the data has been fetched. it also needs to be performed on the main thread.
The call to TableViewController.requestFinished(broadcasts) appears to be sending a message to the TableViewController class rather than to an instance of the TableViewController class, which is wrong. You can't fix that unless your block has access to the instance of TableViewController that you want to send the message to.
You should probably refactor your requestNewBroadcasts method as follows:
Make it not return anything. (The result won't be available until after the async block completes anyway.)
Make requestNewBroadcasts take a completion block (or rather a closure, as they are called in Swift). Get rid of the TableViewController.requestFinished(broadcasts) call entirely, and instead have your network code call the completion block once the network request is complete.
Make your call to dispatch_async use a background queue rather than the main queue so that your task actually runs in the background.
Make your requestNewBroadcasts method invoke the completion block on the main thread.
Each of those steps is going to require work and research on your part.
Figuring out how to add a closure as a parameter will take digging. (See the Swift Programming Language iBook. It explains it well.)
Figuring out how to get a background queue will take work. (See the Xcode docs documentation on GCD. In particular look at dispatch_get_global_queue)
Figuring out how to make a call to the main thread from a background thread will take research (again see the Xcode docs on GCD. Hint: Your current call to dispatch_async is sending your block to a queue on the main thread.).
return broadcasts is executed before the loop that appends data to your array because of DataManager.getBroadcastsFromTweeterWithSuccess's closure.

How to use Core Data synchronously?

I'm trying to make an iOS 8 App with Swift and i need to download data from JSON and save it , but i don't understand Core Data mechanism. (I'm coming from Android with ORM Lite and Windows Phone with sqlite-net).
I'm trying to make two tasks, "GetAllNewsTask" returning all News from database , and "UpdateAllNewsTask" downloading JSON and parsing it, save to database and return all News.
The function getEntitiesFromJson transform parsed JSON string to entity object
class func getEntitiesFromJson(json: JSONValue) -> [NewsEntity]?{
var rList : [NewsEntity] = []
var array = json.array
var countItr = array?.count ?? 0
if(array == nil){
return nil
}
if(countItr > 0){
for index in 0...countItr-1{
var news = NewsEntity()
var jsonVal = array?[index]
news.id = jsonVal?["id"].integer ?? 0
........
rList.append(news)
}
}
return rList
}
GetAllNewsTask (newsDao.findAll() currently return an harcoded empty array, i didn't found how to select all NewsEntity synchronously)
class GetAllNewsTask:NSOperation {
var result : Array<News>?
override func main() -> (){
result = executeSync()
}
func executeSync() -> Array<News>? {
let newsDao = NewsDAO()
let entities = newsDao.findAll()
return NewsModel.getVOsFromEntities(entities)
}
UpdateAllNewsTask
class UpdateAllNewsTask:NSOperation {
var result : Array<News>?
override func main() -> (){
result = executeSync()
}
func executeSync() -> Array<News>? {
let response = JsonServices.getAllNews()
var managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!
var entityDescription = NSEntityDescription.entityForName("NewsEntity", inManagedObjectContext: managedObjectContext)
var entities = NewsModel.getEntitiesFromJson(response)
//TODO insert new, update existing and remove old
return GetAllNewsTask().executeSync()
}
I'm trying to add or update all NewsEntity and delete old, in Java i used List.removeAll(Collection<T>) but i can't found how to do this in Swift.
I got an exception when i override equals and hashcode in NewsEntity class.
Before continuing, is it the correct way to do this ?
If yes there is any good tutorial which demonstrate how to do this?
If no what is the correct way ?
Typically Core Data transactions should always be performed on the object's Managed Object Context thread. For this reason you will see the performBlock and performBlockAndWait calls in NSManagedObjectContext.
Since you are using the main thread you are technically synchronous assuming you are making those update calls on the main thread. If you are not then I would suggest wrapping your synch call into a performBlockAndWait call.
That being said, you should leverage Apple's Documentation on the subject as they explain how you can implement multithreaded core data. You should always perform your server related updates on a background thread.
If you want to implement a removeAll feature you will need to manually fetch all the objects you want to remove and call context.deleteObject(managedObject). Alternatively if you want something more powerful that should enforce cascade deletion, you can set this in your model editor when you select the relationship. The following Delete Rules are available:
Nullify
Cascade
No Action
Deny
Finally, you might find this post useful in explaining some of the commonly used Core Data stack setups and the various performance of each.
Welcome to iOS and good luck:)
EDIT
As an aside you might find Ray Wenderlich provides some great Core Data Tutorials

Resources