In application I am working on, I have to take one element of the array by specifying element's index in the array, like this array[index].
It's a simple UICollectionView which is populated with items I am getting from the array.
In order to guard against Index out of range exception, I am doing this:
guard index < array.count else { return }
return array[index]
Even though I have this guard, I got an Index out of range exception on the array[index] line (but not always).
I don't know how this can happen.
I have even added another check:
extension Collection where Indices.Iterator.Element == Index {
subscript (optional index: Index) -> Iterator.Element? {
return indices.contains(index) ? self[index] : nil
}
}
So I am doing this (this is the actual code snippet from the application):
...
guard let section = chatSections[optional: indexPath.section] else {
return nil
}
guard indexPath.item < section.itemViewModels.count else {
return nil
}
return section.itemViewModels[optional: indexPath.item]
It doesn't always happen, but sometimes I get the Index out of Range exception there.
I was debugging most of the day, trying to figure out conditions when crash happens so I might be able to figure out why, but it seems to happen randomly.
Does anyone have any idea how is this possible? Did anyone encounter this kind of issue?
Are you, by any chance, doing any of your updating from a background thread/queue? If so, make sure your UI interactions are done on the main thread/queue and that you aren't changing the array contents behind your UI's back.
That is, if you're changing the array contents in one queue and trying to update your UI while this is happening, your guard statement could be passing just before the array is modified elsewhere, then by the time the rest of your UI-interacting code executes, the index my no longer be valid.
Without a more complete picture, it's hard to say what's going on, but all these bounds checks you're adding in order to guard against mysteriously-changing array indexes are a big clue to multithreading shenanigans.
I believe you have multiple access to the your data source array (multiple thread try to access add/remove from the array).
to overcome this you should use something to enforce synchronization while accessing your array, there is multiple approce using semaphore or DispatchGroup.
I would recommend to use semaphore since the array is considered as shared resource, example:
private let semaphore = DispatchSemaphore(value: 1)
private var _array:[Item] = []
var array:[Item] {
get {
semaphore.wait()
let result = self._allMessages
defer {
semaphore.signal()
}
return result
}
set {
semaphore.wait()
self. _array = newValue
semaphore.signal()
}
}
and use the array variable to access the array data source not the private _array.
Related
I am using swift, xcode 8.3.3, and XCTest. I am trying to wait for an element to exist on the screen using XCTKVOExpectation. It is always returning the result of timedout (2) even though the element exists.
Here is my code:
func waitForElementToAppear(element: XCUIElement) -> Bool {
let expectation = XCTKVOExpectation(keyPath: "exists", object: element,
expectedValue: true)
let result = XCTWaiter().wait(for: [expectation], timeout: 10)
print(element.exists)
print(result.rawValue)
return result == .completed
}
When I print element.exists, it prints true. However the result.rawValue is 2 (.timedout) Increasing the timeout value did not resolve this either.
I am able to successfully use XCTNSPredicateExpectation:
let myPredicate = NSPredicate(format: "exists == true")
let myExpectation = XCTNSPredicateExpectation(predicate: myPredicate,
object: element)
let result = XCTWaiter().wait(for: [myExpectation], timeout: 10)
return result == .completed
Wondering why XCTKVOExpectation doesn't work though?
Not really an answer, but I've been seeing this in Xcode 9.3.1 as well. The exact same predicate combination works well elsewhere in many places but one in particular almost always times out.
I've worked around it for now by checking whether the object exists before issuing the wait, and then also "result == XCTWaiterResultCompleted || object.exists" (Objective C).
I'd love to know if this is a bug or am I doing something wrong?
I was having the same problem with my own code. I was able to get the KVO change to trigger using didChangeValue(forKey: "keyValuePath").
Since XCTKVOExpectation accepts a String for the key path instead of a KeyPath, paired with needing to call didChangeValue(forKey: "keyValuePath"), it seems XCTKVOExpectation is not meant to work with Swift and is more of a legacy objc object. I just don't think this is going to work in Swift
I'm trying to create a retrying mechanism for our network calls. I have created 2 classes. One a retry Class and another a Manager in case I wanted I can cancel all classes.
class Retry {
var url: String
var maxRetries: Int
init (url: String, retryCount: Int){
self.url = url
self.maxRetries = maxRetries
poll()
RetryManager.shared.add(self)
}
private func poll(){
guard retryCount == 0 else{
print("error")
}
getRequest()
}
private func getRequest(){
// make network request
// if no response is received poll again
}
func cancel(){
maxRetries = 0
}
}
Manager class
class RetryManager{
static let sharedInstance = RetryManager()
var retries : [Retry?] = []
private init(){
}
func register(retry: Retry){
retries.append(retry)
}
func remove(retry: Retry){
retry.cancel() // XX; Do I also need this or just removing it is fine?
retries = retries.filter({$0 !== retry})
}
func cancelAll(){
retries.forEach({$0?.cancel()}) // ZZ; Do I also need this? or just removing them is fine?
retries.removeAll()
}
}
My Retry instances are to be used for making network calls.
My major question is about my cancel mechanism. Will doing a RetryManager.shared.cancelAll() suffice for deallocation? Or I need to run cancel or each cancel instance (ie XX, ZZ are also necessary)?
Currently everything works fine, but I'm not sure if I how it would work if I have multiple pointers...would I need to do:
for index..<retries.count{
retries[index] = nil
}
As far as I understand that won't help, it's same as doing retries.removeAll()
I also read In Swift, how do I set every element inside an array to nil? question but was told to open a new question
Not sure if I can answer your question, but I will try with my best understanding :).
Apple's Swift handbook on Automatic Reference Counting (ARC) covers your question very well.
Usually you don't need to have an array of optionals,
var retries = [Retry]()
...
retries.removeAll()
will nicely remove all containing objects and delete the references to these objects. From your context presented above I do not understand why you need to declare an array of optionals. As you know Swift optionals under the hood are just a typed wrapper class Optional<Type>, which doesn't work around the memory allocation problem.
How does array reference objects?
The array will increase the contained objects' reference count by one, that is, a strong reference.
To ensure the objects in the array to be deallocated, one must make their reference count equal zero. Removing them from the array will do the trick, if nothing else is referencing the contained objects.
Beware of the reference cycle though. In your case, you should not hold reference to the retries array in Retry instance. Otherwise even if you set the retries array to nil, the array and its contained objects still have strong reference to each other, meaning their reference counts will never reduce to zero, causing memory leak.
I have encountered numerous situations where a coder have used the guard keyword. And then later, in a seemingly almost identical situation the same coder in the same code does not use the guard keyword. I am aware that this may be a stupid question, so please don't bash it. When should I use the guard keyword and where shouldn't I?
Here is an example (there are many more). This is part of a script that is requesting data form an API.
//Here I am using guard
guard let json = json else {
//Now I am not using guard
if let error = error {
completion(.Failure(error))
} else {
//Error handling
}
return
}
Why not use the:
if let var1 = var1 {
//Keep on going
} else {
//Don't crash
}
syntax all the time instead of the guard syntax? At first glance it even seems to have more functionality, but I am certain that does not have to be the case.
One great benefit of the guard statement is that you know that if the condition is not satisfied then the execution flow gets stopped.
This is important for several reasons
Unwrapping
You can define unwrapped values which don't need a new scope { ... } to be available
func next(num:Int?) -> Int? {
guard let num = num else { return nil }
return num + 1
}
Readability
When you read the code you know that if the guard condition is not satisfied then the following lines won't be executed.
Semantics
You know a guard statement is there to check conditions required for the following block of code.
But I can replace every guard with an if
Sure. We could also replace every while and for with a goto in some languages. And we could always replace recursion with iteration (and viceversa).
But this doesn't necessarily means it is always a good idea.
Despite we can implement some behaviours with more then one programming "tool", we should still use the one that better fits that specific scenario.
I am really struggling with the fact that someData[start...stop] returns a MutableRandomAccessSlice. My someData was a let to begin with, so why would I want a Mutable thing? Why don't I get just a RandomAccessSlice. What's really frustrating though, is that it returns a thing that is pretty API incompatible with the original source. With a Data, I can use .withUnsafeBytes, but not so with this offspring. And how you turn the Slice back into a Data isn't clear either. There is no init that takes one of those.
I could use the subdata(in:) method instead of subscripting, but then, what's the point of the subscript if I only ever want a sub collection representation that behaves like the original collection. Furthermore, the subdata method can only do open subranges, why the subscript can do both closed and open. Is this just something they haven't quite finished up for Swift3 final yet?
Remember that the MutableRandomAccessSlice you get back is a value type, not a reference type. It just means you can modify it if you like, but it has nothing to do with the thing you sliced it out of:
let x = Data(bytes: [1,2,3]) // <010203>
var y = x[0...1]
y[0] = 2
x // <010203>
If you look in the code, you'll note that the intent is to return a custom slice type:
public subscript(bounds: Range<Index>) -> MutableRandomAccessSlice<Data> {
get {
return MutableRandomAccessSlice(base: self, bounds: bounds)
}
set {
// Ideally this would be:
// replaceBytes(in: bounds, with: newValue._base)
// but we do not have access to _base due to 'internal' protection
// TODO: Use a custom Slice type so we have access to the underlying data
let arrayOfBytes = newValue.map { $0 }
arrayOfBytes.withUnsafeBufferPointer {
let otherData = Data(buffer: $0)
replaceBytes(in: bounds, with: otherData)
}
}
}
That said, a custom slice will still not be acceptable to a function that takes a Data. That is consistent with other types, though, like Array, which slices to an ArraySlice which cannot be passed where an Array is expected. This is by design (and likely is for Data as well for the same reasons). The concern is that a slice "pins" all of the memory that backs it. So if you took a 3 byte slice out of a megabyte Data and stored it in an ivar, the entire megabyte has to hang around. The theory (according to Swift devs I spoke with) is that Arrays could be massive, so you need to be careful with slicing them, while Strings are usually much smaller, so it's ok for a String to slice to a String.
In my experience so far, you generally want subdata(in:). My experimentation with it is that it's very similar in speed to slicing, so I believe it's still copy on write (but it doesn't seem to pin the memory either in my initial tests). I've only tested on Mac so far, though. It's possible that there are more significant performance differences on iOS devices.
Based on Rob's comments, I just added the following pythonesque subscript extension:
extension Data {
subscript(start:Int?, stop:Int?) -> Data {
var front = 0
if let start = start {
front = start < 0 ? Swift.max(self.count + start, 0) : Swift.min(start, self.count)
}
var back = self.count
if let stop = stop {
back = stop < 0 ? Swift.max(self.count + stop, 0) : Swift.min(stop, self.count)
}
if front >= back {
return Data()
}
let range = Range(front..<back)
return self.subdata(in: range)
}
}
That way I can just do
let input = Data(bytes: [0x60, 0x0D, 0xF0, 0x0D])
input[nil, nil] // <600df00d>
input[1, 3] // <0df0>
input[-2, nil] // <f00d>
input[nil, -2] // <600d>
I am implementing showing post part, I want it to do pagination, I got Query part. What I understand is I set limited number of posts when user reached last post that updated in tableView, query fetches more objects by next set limit.
For these, I need something indicates when tableView indexPath is reached at last one or before last one.
I searched some, I think this is good one, but I don't know what does mean.
Get notified when UITableView has finished asking for data?
Could anyone explain me what does mean(how it works) and how to subclass in UITableView's reloadData for this?
fun reloadData() {
print("begin reload")
super.reloadData()
print("end reload")
}
I add my fetching code, I don't think it is working.
var limit = 10
var skip = 0
func fetchAllObjectsFromParse() {
//empty postArray
postsArray = []
//bring data from parse
let query = PFQuery(className: "Posts")
query.limit = limit
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error) -> Void in
if error == nil && objects != nil{
for object in objects! {
self.postsArray.append(object)
}
if (objects!.count == self.limit){
let query = PFQuery(className: "Posts")
self.skip += self.limit
query.skip = self.skip
query.limit = self.limit
print(self.limit)
print(self.skip)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil && objects != nil {
for object in objects! {
self.postsArray.append(object)
print(objects?.count)
}
}
})
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})
}
}else{
print(error?.localizedDescription)
}
}
}
First let's tackle pagination. Now pagination isn't undoable but it does require your server to accept pages so that it knows which set of results to return. For example if you have 100 results in group sizes of twenty, in your url request you'd have to specify if you wanted page 0 - 4.
I would personally recommend using an open-source library to take care of pagination for you. Take a look at MMRecord, it does have some pagination support for you. If you are feeling ambitious and you want to implement it on your own, you'll need to build some networking service, best built on something like AFNetworking that keeps track of the last requested page.
In swift, that would look something like this:
NetworkManager.GET('http://someURI', parameters: [:], page: 0)
Somehow you have to keep the state of which page is next around. A better design, as suggested here, is to use protocols and some sort of datasource wrapper that abstracts the mechanism from the client.
Now you also asked how to detect when a table view scrolls to the end so you can fire off a network request. One way to do it is simple observe scrollViewDidScroll (UITableView inherits from UIScrollView) and check to see if the contentOffset is >= self.tableView.contentSize - self.tableView.frame.size.height (which will be the content offset of when the table is all the way scrolled). However you want the user of your application to be able to keep scrolling without having to scroll to the bottom, waiting for it to load, then continue scrolling so what I would is fire the request when they've scrolled 3/4 down the page or even halfway if you know the request will take a long time. That way by the time they get to the bottom, it'll already have loaded the data and the user will never know the difference.
EDIT:
I would add a few suggestions for you apart from my answer. 1) Take a look at this: http://artsy.github.io/blog/2015/09/24/mvvm-in-swift/
It talks about the MVVM design pattern which is much better for holding state instead of having state variables in your view controller.
2) your function, fetchAllObjectsFromParse is a bad name for a couple of reasons. First, the name implies that the function fetches all the objects at once, which isn't the case if you want it paginated.
Maybe something like this:
func fetchObjectsForModel(model: String, atPage page: Int, withBlock block: ([PFObejct], NSError?) -> Void {
}
And then make another function which will generate your query:
func generateQueryWithSkips(skip: Int, limit: Int) -> PFQuery {}