Insufficient space allocated to copy array contents - arrays

I am building up some code to request multiple information from a database in order to have a time table in my front end incl. multiple DB requests.
The problem is that with one particular request where . am using swiftKuery and DispatchGroups i receive ooccasionally but not always an error message in my XCode. This can not be reconstructed by different request but just sometimes happens.
here is a snippet of my code.
var profWorkDaysBreak = [time_workbreaks]()
let groupServiceWorkDayBreaks = DispatchGroup()
...
///WorkdaysBreakENTER AsyncCall
//UnreliableCode ?
profWorkDays.forEach {workDay in
groupServiceWorkDayBreaks.enter()
time_workbreaks.getAll(weekDayId: workDay.id) { results, error in
if let error = error {
print(error)
}
if let results = results {
profWorkDaysBreak.append(contentsOf: results) // The error happens here !
}
groupServiceWorkDayBreaks.leave()
}
}
...
groupServiceWorkDayBreaks.wait()
The results and profWorkDaysBreak variables are the same just sometimes i receive the message:
Fatal error: Insufficient space allocated to copy array contents
This leads to a stop of the execution.
I assume, that maybe the loop might sometimes finish an earlier execution in the DispatchGroup ??? but this is the only think i have as an idea....

Most likely this is caused by some race conditions due to the fact that you modify the array from multiple threads. And if two threads happen to try and alter the array at the same time, you get into problems.
Make sure you serialize the access to the array, this should solve the problem. You can use a semaphore for that:
var profWorkDaysBreak = [time_workbreaks]()
let groupServiceWorkDayBreaks = DispatchGroup()
let semaphore = DispatchSemaphore(value: 0)
...
profWorkDays.forEach { workDay in
groupServiceWorkDayBreaks.enter()
time_workbreaks.getAll(weekDayId: workDay.id) { results, error in
if let error = error {
print(error)
}
if let results = results {
// acquire the lock, perform the non-thread safe operation, release the lock
semaphore.wait()
profWorkDaysBreak.append(contentsOf: results) // The error happens here !
semaphore.signal()
}
groupServiceWorkDayBreaks.leave()
}
}
...
groupServiceWorkDayBreaks.wait()
The semaphore here acts like a mutex, allowing at most one thread to operate on the array. Also I would like to emphasise the fact that the lock should be hold for the least amount of time possible, so that the other threads don't have to wait for too much.

Here is the only way i got my code running reliable so far..
i skipped contents of completely and just went to a forEach Loop
var profWorkDaysBreak = [time_workbreaks]()
let groupServiceWorkDayBreaks = DispatchGroup()
...
///WorkdaysBreakENTER AsyncCall
//UnreliableCode ?
profWorkDays.forEach {workDay in
groupServiceWorkDayBreaks.enter()
time_workbreaks.getAll(weekDayId: workDay.id) { results, error in
if let error = error {
print(error)
}
if let results = results {
results.forEach {profWorkDayBreak in
profWorkDaysBreak.append(profWorkDayBreak)
}
/*
//Alternative causes error !
profWorkDaysBreak.append(contentsOf: results)
*/
}
groupServiceWorkDayBreaks.leave()
}
}
...
groupServiceWorkDayBreaks.wait()

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.

Unable to delete all current elements of core data database

I am trying to delete all the data in my core data database but it is throwing up an error and is not affecting the SQLite database at all.
if self.userCredentials.count > 0 {
for loopIndex in 0 ... self.userCredentials.count - 1 {
self.context.delete(self.userCredentials[loopIndex])
self.userCredentials.remove(at: loopIndex)
}
self.saveLogin()
}
func saveLogin() {
do {
try context.save()
print ("Context saved successfully")
}
catch {
print ("Error saving items \(error)")
}
}
Fatal Error: Index out of range
Change your code to:
for userCredential in userCredentials {
context.delete(userCredential)
}
saveLogin()
The problem with your code is that you loop the amount of times of elements that variable userCredentials holds. That is an immutable value which won't be changed and it initialized before it looped even once.
You are accessing the index of an array based on the index. That's not wrong, but shouldn't be done in cases in which a simple for-in (see code above) is sufficient.
After that, you manipulate the element count by removing an element. That doesn't effect the immutable element count that I stated above. Because of that, soon or later you get an index out of bounds exception. You should try to search for what that exactly is, you try to access an element in a list which does not exists.

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))")
}
})
}
}
}

Method For Ending A Loop With Completion Handler?

Perhaps I have an underlying issue understanding the overall premise, but I am trying to figure out the best approach to do something with an array of items, and end the test early once a certain criteria is found.
For example, I have an array of names;
var names = ["Bob", "Billy", "Sarah", "Brandon", "Brian", "Rick"]
I would like to test each name in the array and see if it exists in a database. To do this, I'm calling another function with a completion handler;
for name in names {
TestName(name) { response in
if response {
// END THE LOOP
} else {
// KEEP GOING
}
}
I've not been able to figure out the // END THE LOOP. For the purposes of this example, I'm only concerned when the response is true the first time (if Billy exists in the array, I have no further interest in testing Sarah, Brandon, Brian, or Rick).
Thank you!
Before you start the loop, set a flag:
var exitEarly = false
for name in names {
Test the flag each time thru the loop:
for name in names {
if exitEarly {
break
}
In the TestName response block, set the flag:
TestName(name) { response in
if response {
exitEarly = true
} else {
// KEEP GOING
}
}
Note, however, that if TestName's block is executed asynchronously, that won't work, because the whole loop precedes the calling of any of the asynchronous blocks (that is the nature of asynchronous-ness).
Your case isn't really what a loop is designed for. It's possible that the loop may finish before the closures within the loop are executed.
Instead, try a recursive function with a completion block:
func databaseHasAName(names: [String], index: Int, completion: (String?) -> ()) {
guard index < names.count else{
completion(nil)
return
}
let name = names[index]
TestName(name) { response in
if response {
completion(name)
} else {
databaseHasName(names, index: index + 1, completion: completion)
}
}
}
This insures that only one call is happening at a time, regardless of the synchronicity of the response block
Add the #noescape attribute to TestName's closure parameter to indicate that the closure does not escape the call.
Use a variable outside the TestName call, set to false, and set it to true inside the loop if you want to stop.
After the TestName call, check the variable to see if you need to break.
or
Change TestName to return a value indicating if it should proceed or not
I had to do the same thing as PEEJWEEJ. My async tasks are web queries and parsing and quite intensive and the for loop always finished before those tasks did so there was no way to stop them.
So I converted it to recursive and set a flag when I wanted it to stop and it works fine now.
// ************************************************************************************************************
// MARK: Recursive function
// I changed the loop to be recursive so I could stop when I need to - i.e. when selecting another race
// I set the stopFetching flag in the seque when changing races and the current set of BG queries stops
// ************************************************************************************************************
func getRaceResultsRecursive(race: Race, bibs: [Bib], index: Int, completion: #escaping (Bool?) -> ())
{
guard index < bibs.count else{
completion(nil)
return
}
var url: URL
self.stopFetching = false
let bibID = bibs[index]
url = self.athleteResultAPI.formatURL(baseURL: (race.baseURL)!,
rd: (race.rdQueryItem)!,
race: (race.raceQueryItem)!,
bibID: "\(bibID.bib!)",
detail: (race.detailQueryItem)!,
fragment: (race.detailQueryItem)!,
webQueryType: (race.webQueryType!))
self.athleteResultAPI.fetchAthleteResults(url: url, webQueryType: race.webQueryType!)
{
(athleteReturnCode) in
switch athleteReturnCode
{
case let .success(athleteResult):
self.athleteResults.append(athleteResult) // Add to collection
self.delegate?.athleteResultsUpdated() // update Delegate to notify of change
case let .failure(error):
print(error)
break
}
if self.stopFetching {
completion(true)
}
else {
self.getRaceResultsRecursive(race: race, bibs: bibs, index: index + 1, completion: completion)
}
}
}
// ************************************************************************************************************
// getRaceResults
// Get all the bibs to track for this race from the iCloudKit database
// ************************************************************************************************************
func getRaceResults(race: Race)
{
// get all the races and bibs an put in the Races Store
raceStore.fetchBibsForRace(race: race, foreignKey: race.recordID)
{
(results, error) in
if let error = error {
print("Error in fetchBibsForRace(): \(error)")
return
}
// clear the store since we are on a new race
self.athleteResults.removeAll()
self.getRaceResultsRecursive(race: race, bibs: race.bibs, index: 0)
{
(stopFetching) in
return
}
}
}

Behavior of initial.min.cluster.size

Is Hazelcast always blocking in case initial.min.cluster.size is not reached? If not, under which situations is it not?
Details:
I use the following code to initialize hazelcast:
Config cfg = new Config();
cfg.setProperty("hazelcast.initial.min.cluster.size",Integer.
toString(minimumInitialMembersInHazelCluster)); //2 in this case
cfg.getGroupConfig().setName(clusterName);
NetworkConfig network = cfg.getNetworkConfig();
JoinConfig join = network.getJoin();
join.getMulticastConfig().setEnabled(false);
join.getTcpIpConfig().addMember("192.168.0.1").addMember("192.168.0.2").
addMember("192.168.0.3").addMember("192.168.0.4").
addMember("192.168.0.5").addMember("192.168.0.6").
addMember("192.168.0.7").setRequiredMember(null).setEnabled(true);
network.getInterfaces().setEnabled(true).addInterface("192.168.0.*");
join.getMulticastConfig().setMulticastTimeoutSeconds(MCSOCK_TIMEOUT/100);
hazelInst = Hazelcast.newHazelcastInstance(cfg);
distrDischargedTTGs = hazelInst.getList(clusterName);
and get log messages like
debug: starting Hazel pullExternal from Hazelcluster with 1 members.
Does that definitely mean there was another member that has joined and left already? It does not look like that would be the case from the log files of the other instance. Hence I wonder whether there are situtations where hazelInst = Hazelcast.newHazelcastInstance(cfg); does not block even though it is the only instance in the hazelcast cluster.
The newHazelcastInstance blocks till the clusters has the required number of members.
See the code below for how it is implemented:
private static void awaitMinimalClusterSize(HazelcastInstanceImpl hazelcastInstance, Node node, boolean firstMember)
throws InterruptedException {
final int initialMinClusterSize = node.groupProperties.INITIAL_MIN_CLUSTER_SIZE.getInteger();
while (node.getClusterService().getSize() < initialMinClusterSize) {
try {
hazelcastInstance.logger.info("HazelcastInstance waiting for cluster size of " + initialMinClusterSize);
//noinspection BusyWait
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
} catch (InterruptedException ignored) {
}
}
if (initialMinClusterSize > 1) {
if (firstMember) {
node.partitionService.firstArrangement();
} else {
Thread.sleep(TimeUnit.SECONDS.toMillis(3));
}
hazelcastInstance.logger.info("HazelcastInstance starting after waiting for cluster size of "
+ initialMinClusterSize);
}
}
If you set the logging on debug then perhaps you can see better what is happening. Member joining and leaving should already be visible under info.

Resources