Property does not persist in array? - arrays

My goal is to persist a swift-nio Scheduled instance in a struct named Receiver in an array to potentially use later. It creates the Receiver, stores it in the array and adds the Scheduled instance, but the Receiver instance in the array does not contain the Scheduled instance.
What could be causing this and how could I fix it?
It does not occur with anything else and the task associated with the Scheduled instance still executes. The XCode debugger even shows the instance in the Receiver associated with a variable, yet not in the array.
private var receivers: Array<Receiver>
func connect() {
var entry = Receiver(
// ...
)
receivers.append(entry)
connect(&entry)
}
func connect(_ device: inout Receiver) {
startTimeout(&device)
// device contains timeout, but receivers[0] does not
}
private func startTimeout(_ entry: inout Receiver) {
stopTimeout(&entry) // Does nothing initially (timeout not yet set)
var device = entry
// The timeout is added once here
entry.timeout = entry.eventLoop.scheduleTask(in: .seconds(10), {
print("Receiver timeout occurred")
self.reconnect(&device)
return 0
})
}
func someStuff() {
// This does not work. timeout is nil, the timeout still occurs
stopTimeout(&entry) // Cancels the Scheduled timeout
}
struct Receiver {
var timeout: Scheduled<Any>?
}

Your struct Receiver is a value type. Everytime it is passed it gets copied (a new instance is created). Manipulating it will alter only the new instance. You avoided that by using inout parameters.
But with:
receivers.append(entry)
you are appending a new instance to the array. Modifing entry later on will not affect the instance in the array.
In this case you should use a class.
class Receiver {
var timeout: Scheduled<Any>?
}

Related

My function returns empty array in swift and parse

HI there I am writing a function to get data from my parse server in swift everything is working alright and the data is getting read well. but when I try to return the array it returns me an empty array.
I also added a print in the "Get data in background" and there, the array was getting full.So the problem is not getting the data.
public func getthearray() -> Array<UIImage>
{
let user = PFUser.current()
let array = user?["Photos"] as! Array<PFFileObject>
var imagearray = [UIImage]()
for x in array
{
x.getDataInBackground
{ (dataa, error) in
var img = UIImage(data: dataa!)
imagearray.append(img!)
}
}
return imagearray
}
The reason the function returns an empty array is the fact that the code in the x.getDataInBackground completion gets called asynchronously, and before any image will get added to the array, the faction will already return.
Here is the solution (in 2 versions), which is your function slightly refactored and rewritten with completion handler and Grand Central Dispatch
Approach 1. Semaphores
public func getTheArray(_ completion: #escaping ([UIImage]) -> Void) {
let user: PFUser = .current()
let array = user?["Photos"] as? [PFFileObject] ?? []
var result = [UIImage]()
let semaphore = DispatchSemaphore(value: 0)
// dispatch to a separate thread which we can safely occupy and block
// while waiting for the results from async calls.
DispatchQueue.global().async {
for file in array {
file.getDataInBackground { (data, error) in
if let data = data, let image = UIImage(data: data) {
result.append(image)
}
// the result have arrived, signal that we are ready
// to move on to another x
semaphore.signal()
}
// wait until the `signal()` is called, thread is blocked
semaphore.wait()
}
// dispatch to main queue where we are allowed to perform UI updates
DispatchQueue.main.async {
// call the completion, but we are doing it only once,
// when the function is finished with its work
completion(result)
}
}
}
Approach 2. Dispatch Groups
public func getTheArray(_ completion: #escaping ([UIImage]) -> Void) {
let user: PFUser = .current()
let array = user?["Photos"] as? [PFFileObject] ?? []
var result = [UIImage]()
let group = DispatchGroup()
for file in array {
group.enter()
file.getDataInBackground { (data, error) in
if let data = data, let image = UIImage(data: data) {
result.append(image)
}
group.leave()
}
}
// notify once all task finish with `leave()` call.
group.notify(queue: .main) {
// call the completion, but we are doing it only once,
// when the function is finished with its work
completion(result)
}
}
Usage
and you would call it like this
getTheArray { result in
// do what you want with result which is your array of UIImages
}
Documentation:
DispatchQueue
DispatchSemaphore
Relevant blogposts:
Grand Central Dispatch by John Sundell
A deep dive into Grand Central Dispatch in Swift by John Sundell
You should use the completion handler closure as discussed by others, in order to asynchronously return the array of images when all the requests are done.
The general pattern is:
Use #escaping completion handler closure.
Use dispatch group to keep track of all of the asynchronous requests.
Store the results in a dictionary as the individual requests finish. We use a dictionary for the results, because with concurrent requests, you do not know in what order the requests will finish, so we will store it in a structure from which we can efficiently retrieve the results later.
Use dispatch group notify closure, to specify what should happen when all the requests are done. In this case, we will build a sorted array of images from our unsorted dictionary, and call the completion handler closure.
As an aside, one should avoid using forced unwrapping operator (the ! or as!), especially when dealing with network requests, whose success or failure is outside of your control. We would generally use guard statement to test that the optionals were safely unwrapped.
Thus:
func fetchImages(completion: #escaping ([UIImage]) -> Void) {
guard
let user = PFUser.current(),
let files = user["Photos"] as? [PFFileObject]
else {
completion([])
return
}
var images: [Int: UIImage] = [:] // dictionary is an order-independent structure for storing the results
let group = DispatchGroup() // dispatch group to keep track of asynchronous requests
for (index, file) in files.enumerated() {
group.enter() // enter the group before asynchronous call
file.getDataInBackground { data, error in
defer { group.leave() } // leave the group when this completion handler finishes
guard
let data = data,
let image = UIImage(data: data)
else {
return
}
images[index] = image
}
}
// when all the asynchronous tasks are done, this `notify` closure will be called
group.notify(queue: .main) {
let array = files.indices.compactMap { images[$0] } // now rebuild the ordered array
completion(array)
}
}
And, you'd use it like so:
fetchImages { images in
// use `images` here, e.g. if updating a model object and refreshing the UI, perhaps:
self.images = images
self.tableView.reloadData()
}
// but not here, because the above runs asynchronously (i.e. later)
But the idea is to embrace asynchronous patterns given that we are calling an asynchronous API, and use dispatch groups to keep track of when they are all done. But dispatch semaphores are generally discouraged, as they force the requests to be performed sequentially, one after another, which will slow it down (e.g., in my experience, between two and five times slower).
As an aside, we would generally want to report success or failure. So rather than [UIImage], we would have the closure’s parameter to be a Result<[UIImage], Error> (if you want a single Error) or [Result<UIImage, Error>] if you want either a UIImage or Error for each file. But there’s not enough here to know what error handling you want. But just a FYI.
While I've answered the tactical question above, we really should ask how many images might you be dealing with. If you are retrieving lots of images and/or the user is on a slow connection, this pattern (known as “eager” fetching of the images) is discouraged. First, it can be slow if there are a lot of them. Second, images take up a lot of memory, and you might not want to load all of them if you only need a subset of them at any given point in time. We would often refactor our app to employ “lazy” fetching of the images, retrieving them as needed, not all up front. Or, if you want to do eager fetch, download the assets as files to caches folder (reducing RAM consumption) and create UIImage instances when required in the UI.

For-loop isn't returning the items in an array in the correct order

I have an array of Integers that I need to loop through that then make a network request for further information and with the returned information populate an array of a new object I have created.
I want the returned data to come back in the same order in which the array provides it in, however it is coming back in a different order and am assuming it might have something to do with the network request.
I'm new(ish) to development, so the answer may be very obvious, but I'm really at a dead end with what to do next.
I've tried adding delays to the network request on each loop, i've tried calling .sort() on the array to ensure the array stays in the correct order
var tacticalCoverIdArray = [Int]()
var savedTacticalCoverData = [Covers]()
for coverID in tacticalCoverIdArray {
performGetRequestForSpecificCovers(coverID: coverID, targetURL: targetURL, completion: { (data, HTTPSatusCode, error) -> Void in
if HTTPSatusCode == 200 && error == nil {
do {
if coverID != 0 {
let decodedJSON = try JSONDecoder().decode([Covers].self, from: data)
savedTacticalCoverData.append(decodedJSON[0])
} else {
let data = Covers(id: 0, game: 0, image_id: "")
savedTacticalCoverData.append(data)
}
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000), execute: {
saveTacticalCoverData()
})
} catch let error {
print("Error decoding JSON: \(error)")
}
} else {
print("HTTP status code error: \(HTTPSatusCode)")
print("Error loading data: \(String(describing: error))")
}
})
}
When putting a print statement under the very first declaration of the for-loop (i.e: print(coverID) the return is what I would expect, in which it loops through each integer and then returns them in order.
However, as soon as I put the same print statement under the 'performGetRequestForSpecificCovers' method, the coverID array is not in the order that it should be in, and therefore I get my returned values in an incorrect order when I append them to my 'savedTacticalCoverData' array.
Your hunch about the network requests having an impact on the ordering seems correct.
What I'm guessing is happening here is that when you are looping over tacticalCoverIdArray and calling performGetRequestForSpecificCovers(), that loop doesn't wait for that network request to complete and for the completion block to get called. It continues with the next iteration. Effectively, you are sending tacticalCoverIdArray.count network requests in parallel. Those completion blocks get called much later, long after the outer loop is complete, and most likely even on a different thread.
The most basic, and worst, option is to use DispatchSemaphore to hold up the outer loop until the completion block is called. You'd create a semaphore, call semaphore.signal() inside the completion handler, and call semaphore.wait() at the end of every loop iteration. The problem with this approach is that you will wait for each network request to complete before proceeding to the next one. Also, you will tie up the thread that is executing the first outer loop, and threads are a finite resource, so it's not a good idea to waste them.
A better option is to dispatch all requests at once, and handle the out-of-order responses. This will complete much faster than serially dispatching them, unless you encounter some kind of limitations with dispatching so many network requests in parallel. Instead of savedTacticalCoverData being an array, perhaps it could be a dictionary, where the key is the index of the outer loop, and the value is what you're trying to save? Each time the completion handler gets called, you could check whether or not the dictionary is full and you've accumulated all of the responses you want, and only then proceed with the final "everything is done" action, presumably saveTacticalCoverData().
You'll have to be careful to get your multithreading right. Unless performGetRequestForSpecificCovers() uses only one callback queue, and it's the same queue that this function is running on, you might get called on different threads. If that's the case, I would recommend making a new DispatchQueue and always operating on your dictionary only from that queue, to ensure consistency when those completion blocks come in on random threads. Something like this:
class MyClass {
var tacticalCoverIdArray = [Int]()
var savedTacticalCoverData = [Int: Covers]()
var queue = DispatchQueue(label: "Class Internal Queue")
func myFunc() {
// ... fill in the blanks here
for (index, coverID) in tacticalCoverIdArray.enumerated() {
performGetRequestForSpecificCovers(coverID: coverID, targetURL: targetURL, completion: { (data, HTTPSatusCode, error) -> Void in
if HTTPSatusCode == 200 && error == nil {
do {
queue.async {
if coverID != 0 {
let decodedJSON = try JSONDecoder().decode([Covers].self, from: data)
self.savedTacticalCoverData[index] = decodedJSON[0]
} else {
let data = Covers(id: 0, game: 0, image_id: "")
self.savedTacticalCoverData[index] = data
}
if self.savedTacticalCoverData.count == self.tacticalCoverIdArray.count {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000), execute: {
self.saveTacticalCoverData()
})
}
}
} catch let error {
print("Error decoding JSON: \(error)")
}
} else {
print("HTTP status code error: \(HTTPSatusCode)")
print("Error loading data: \(String(describing: error))")
}
})
}
}
}

Preventing completion handler to be executed synchronously

I'm writing some networking code in Swift that prevents initiating a download that is already in progress. I do this by keeping tracking of the identity of the network request along with the associated completion handlers in an (synchronized) array A. When a network call finishes it calls the completion handlers that are associated with that resource and it subsequently removes those handlers from the array A.
I want to make sure there is no way for threads to access the array in certain cases. For example, consider the following scenario:
A request to download resource X is started.
Verify whether the request has already been made.
Add the completion handler to the array A.
If request has not been made, start the download.
What if resource X was already downloading, and the completion handler for this download interrupts the thread between steps 2 and 3? It has been verified that the request has been made so the download will not be started, but the new completion handler will be added to array A which will now never be called.
How would I block this from happening? Can I lock the array for writing while I do steps 2 and 3?
The simple solution is to run everything on the main thread except the actual downloading. All you need to do is make the completion handler a stub that places a block on the main queue to do all the work.
The pseudo code for what you want is something like
assert(Thread.current == Thread.main)
handlerArray.append(myHandler)
if !requestAlreadyRunning)
{
requestAlreadyRunning = true
startDownloadRequest(completionHandelr: {
whatever in
Dispatch.main.async // This is the only line of code that does not run on the main thread
{
for handler in handlerArray
{
handler()
}
handlerArray = []
requestAlreadyRunning = false
}
})
}
This works because all the work that might result in race conditions and synchronisation conflicts runs on one thread - the main thread and so the completion handler can't possibly be running when you are adding new completion handlers to the queue and vice versa.
Note that, for the above solution to work, your application needs to be in a run loop. This will be true for any Cocoa based application on Mac OS or iOS but not necessarily true for a command line tool. If that is the case or if you don't want any of the work to happen on the main thread, set up a serial queue and run the connection initiation and the completion handler on it instead of the main queue.
I'm working on the assumption that you want to be able to add multiple callbacks that will all be run when the latest request completes, whether it was already in-flight or not.
Here's a sketch of a solution. The basic point is to take a lock before touching the array(s) of handlers, whether to add one or to invoke them after the request has completed. You must also synchronize the determination of whether to start a new request, with the exact same lock.
If the lock is already held in the public method where the handlers are added, and the request's own completion runs, then the latter must wait for the former, and you will have deterministic behavior (the new handler will be invoked).
class WhateverRequester
{
typealias SuccessHandler = (Whatever) -> Void
typealias FailureHandler = (Error) -> Void
private var successHandlers: [SuccessHandler] = []
private var failureHandlers: [FailureHandler] = []
private let mutex = // Your favorite locking mechanism here.
/** Flag indicating whether there's something in flight */
private var isIdle: Bool = true
func requestWhatever(succeed: #escaping SuccessHandler,
fail: #escaping FailureHandler)
{
self.mutex.lock()
defer { self.mutex.unlock() }
self.successHandlers.append(succeed)
self.failureHandlers.append(fail)
// Nothing to do, unlock and wait for request to finish
guard self.isIdle else { return }
self.isIdle = false
self.enqueueRequest()
}
private func enqueueRequest()
{
// Make a request however you do, with callbacks to the methods below
}
private func requestDidSucceed(whatever: Whatever)
{
// Synchronize again before touching the list of handlers and the flag
self.mutex.lock()
defer { self.mutex.unlock() }
for handler in self.successHandlers {
handler(whatever)
}
self.successHandlers = []
self.failureHandlers = []
self.isIdle = true
}
private func requestDidFail(error: Error)
{
// As the "did succeed" method, but call failure handlers
// Again, lock before touching the arrays and idle flag.
}
}
This is so broadly applicable that you can actually extract the callback storage, locking, and invocation into its own generic component, which a "Requester" type can create, own, and use.
Based on Josh's answer I created a generic Request & Requester below. It had a few more specific needs than I described in the question above. I want the Request instance to manage only requests with a certain ID (which I made into a String for now, but I guess this could also made more generic). Different ID's require a different Request instance. I created the Requester class for this purpose.
The requester class manages an array of Requests. For example, one could choose T = UIImage, and ID = image URL. This would give us an image downloader. Or one could choose T = User, and ID = user id. This would get a user object only once, even when requested several times.
I also wanted to be able to cancel requests from individual callers. It tags the completion handler with a unique ID that is passed back to the caller. It can use this to cancel the request. If all callers cancel, the request is removed from the Requester.
(The code below has not been tested so I cannot guarantee it to be bug free. Use at your own risk.)
import Foundation
typealias RequestWork<T> = (Request<T>) -> ()
typealias RequestCompletionHandler<T> = (Result<T>) -> ()
typealias RequestCompletedCallback<T> = (Request<T>) -> ()
struct UniqueID {
private static var ID: Int = 0
static func getID() -> Int {
ID = ID + 1
return ID
}
}
enum RequestError: Error {
case canceled
}
enum Result<T> {
case success(T)
case failure(Error)
}
protocol CancelableOperation: class {
func cancel()
}
final class Request<T> {
private lazy var completionHandlers = [(invokerID: Int,
completion: RequestCompletionHandler<T>)]()
private let mutex = NSLock()
// To inform requester the request has finished
private let completedCallback: RequestCompletedCallback<T>!
private var isIdle = true
// After work is executed, operation should be set so the request can be
// canceled if possible
var operation: CancelableOperation?
let ID: String!
init(ID: String,
completedCallback: #escaping RequestCompletedCallback<T>) {
self.ID = ID
self.completedCallback = completedCallback
}
// Cancel the request for a single invoker and it invokes the competion
// handler with a cancel error. If the only remaining invoker cancels, the
// request will attempt to cancel
// the associated operation.
func cancel(invokerID: Int) {
self.mutex.lock()
defer { self.mutex.unlock() }
if let index = self.completionHandlers.index(where: { $0.invokerID == invokerID }) {
self.completionHandlers[index].completion(Result.failure(RequestError.canceled))
self.completionHandlers.remove(at: index)
if self.completionHandlers.isEmpty {
self.isIdle = true
operation?.cancel()
self.completedCallback(self)
}
}
}
// Request work to be done. It will only be done if it hasn't been done yet.
// The work block should set the operation on this request if possible. The
// work block should call requestFinished(result:) if the work has finished.
func request(work: #escaping RequestWork<T>,
completion: #escaping RequestCompletionHandler<T>) -> Int {
self.mutex.lock()
defer { self.mutex.unlock() }
let ID = UniqueID.getID()
self.completionHandlers.append((invokerID: ID, completion: completion))
guard self.isIdle else { return ID }
work(self)
self.isIdle = false
return ID
}
// This method should be called from the work block when the work has
// completed. It will pass the result to all completion handlers and call
// the Requester class to inform that this request has finished.
func requestFinished(result: Result<T>) {
self.mutex.lock()
defer { self.mutex.unlock() }
completionHandlers.forEach { $0.completion(result) }
completionHandlers = []
self.completedCallback(self)
self.isIdle = true
}
}
final class Requester<T> {
private lazy var requests = [Request<T>]()
private let mutex = NSLock()
init() { }
// reuqestFinished(request:) should be called after a single Request has
// finished its work. It removes the requests from the array of requests.
func requestFinished(request: Request<T>) {
self.mutex.lock()
defer { self.mutex.unlock() }
if let index = requests.index(where: { $0.ID == request.ID }) {
requests.remove(at: index)
}
}
// request(ID:, work:) will create a request or add a completion handler to
// an existing request if a request with the supplied ID already exists.
// When a request is created, it passes a closure that removes the request.
// It returns the invoker ID to the invoker for cancelation purposes.
func request(ID: String,
work: #escaping RequestWork<T>,
completion: #escaping RequestCompletionHandler<T>) ->
(Int, Request<T>) {
self.mutex.lock()
defer { self.mutex.unlock() }
if let existingRequest = requests.first(where: { $0.ID == ID }) {
let invokerID = existingRequest.request(work: work, completion: completion)
return (invokerID, existingRequest)
} else {
let request = Request<T>(ID: ID) { [weak self] (request) in
self?.requestFinished(request: request)
}
let invokerID = request.request(work: work, completion: completion)
return (invokerID, request)
}
}
}

Rx Swift simple timer not working

I have this RxSwift code in swift 3
let bag:DisposeBag = DisposeBag()
var sig:Observable<Int>!
sig = Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)
sig.subscribe(onNext: { (milsec) in
print("Mil: \(milsec)")
}).addDisposableTo(bag)
i run this code when button tapped, but its not print anything on console.
DisposeBag will dispose of your subscription once it goes out of scope. In this instance, it'll be right after the call to subscribe, and it explains why you don't see anything printed to the console.
Move the definition of dispose bag to the class creating the subscription and everything should work fine.
class MyViewController: UIViewController {
let bag:DisposeBag = DisposeBag()
dynamic func onButtonTapped() {
var sig:Observable<Int>!
sig = Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)
sig.subscribe(onNext: { (sec) in
print("Sec: \(sec)")
}).addDisposableTo(bag)
}
}
On a side note, interval expects an interval in seconds, so it will only tick every seconds as oposed to milliseconds.

Adding values to Array in Swift Class but Array claims it is empty when tested

I am trying to make an array of integers with data I have stored on an online database (Parse). I know for a fact that I am receiving the data and that my variable is storing that data. I also know for a fact that the data value is being added as when I print out the size of the array under my append line, the size constantly increases until it reaches the size of my database (90). However, when I print the size of the array at the end of the method or in my constructor, I get a value of 0. I have a feeling that this problem is happening because of the "self" keyword but I am not sure how to get around it. My end goal is store all the values from the database into an array that I create and can globally access.
Here is the code:
import Foundation
class DataLoader
{
var allData: [Int] = []
init()
{
allData = []
generateAllData()
println(allData.count)
}
private func generateAllData()
{
var tempVal: Int = 0
var tempArray: [Int] = []
Parse.setApplicationId("CENSORED FOR PRIVACY REASONS", clientKey: "CENSORED FOR PRIVACY REASONS")
var query = PFQuery(className: "Snapshot")
query.selectKeys(["objectID"])
query.findObjectsInBackgroundWithBlock
{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil
{
for obj in objects
{
var temp: String = obj.objectId
var newQuery = PFQuery(className: "Data")
newQuery.getObjectInBackgroundWithId(temp)
{
(dataValue: PFObject!, error: NSError!) -> Void in
if error == nil && dataValue != nil
{
tempVal = dataValue["Year"].integerValue
}
else
{
println(error)
}
}
self.allData.append(tempVal)
println(self.allData.count)
}
}
}
println(allData.count)
}
}
The problem is that the println's at the end of the method and the end of the init are happening while the background operation is still getting the data.
When you call "query.findObjectsInBackgroundWithBlock", it will go off into the background and get the data. But that does not block the next line from being called and it does not stop the function returning.
I suggest you add a callback or delegate method so that the rest of your code knows when the data has completely downloaded.
And you use of "self" is correct. Inside a block, you have to provide that context.
Update:
Adding more info about blocks and callbacks.
When you are using a block, the code after the block continues on without waiting for the block to complete. So a good way to know when the block has finished it to send a callback function as one of the parameters to the function containing the block. Once the block has completed, it can use the callback function to report back.
As a shorter example than your code, have a look at this animation function:
doSomeAnimation() // call the function below
func doSomeAnimation() {
println("Starting doSomeAnimation")
UIView.animateWithDuration(2.0,
animations: { () -> Void in
// animate something here
self.alphaButton.alpha = 1.0
}) { (animationDone) -> Void in
// animation over
println("Animation complete")
}
println("Ending doSomeAnimation")
}
You will see it contains 3 println() statements and the order in which they appear may surprise you:
Starting doSomeAnimation
Ending doSomeAnimation
Animation complete
So the doSomeAnimation() function is over long before the animation has completed. In this trivial example, that doesn't matter, but what if you need to know before the rest of your code could proceed?
One solution is to send a callback function to the function with the block. Here is the previous example with a callback in place:
doSomeAnimation() { (complete : Bool) in
println("Animation callback")
}
func doSomeAnimation(callback : ( Bool ) -> Void) {
println("Starting doSomeAnimation")
UIView.animateWithDuration(2.0,
animations: { () -> Void in
// animate something here
self.alphaButton.alpha = 1.0
}) { (animationDone) -> Void in
// animation over
println("Animation complete")
callback(animationDone)
}
println("Ending doSomeAnimation")
}
So the doSomeAnimation() function is called, but it is provided with a function as its parameter. It performs the animation and when the animation has finished, it uses this supplied callback function to report back to the caller.
And now the println() statements show as follows:
Starting doSomeAnimation
Ending doSomeAnimation
Animation complete
Animation callback
Hopefully this makes it clearer, both what the issue is an a possible solution.

Resources