Add elements to array each time a particular function is called - ios

I am working on an audio-recording application. Each time I stop the recording, I need to add the recording filename to an array.
Currently, only one element gets added and when I add the next element, I am not able to see the previous element that had been added.
Am I missing something?
func pushDummyUploadCell(pendingUploadModel: String) {
var pendingUploadModels: [String] = []
if !queueAllFailedRecordings {
pendingUploadModels.append(pendingUploadModel)
print("Queue:",pendingUploadModels.count,"elements:",[pendingUploadModels]) //each time returns 1
}
else {
pendingUploadModels = [pendingUploadModel]
}
}
I am calling this function once I stop the recording.

You just need to define your array as globle in your controller or class.
var pendingUploadModels: [String] = []
func pushDummyUploadCell(pendingUploadModel: String) {
if !queueAllFailedRecordings {
pendingUploadModels.append(pendingUploadModel)
print("Queue:",pendingUploadModels.count,"elements:",[pendingUploadModels]) //each time returns 1
}
else {
pendingUploadModels = [pendingUploadModel]
}
}

Related

Randomly Rearrange items in a LazyRow - Jetpack Compose

I have a LazyRow. Everything works fine. I just want the items to be randomly rearranged every time this LazyRow is drawn on the screen. Here is my code:
LazyRow(
reverseLayout = true,
contentPadding = PaddingValues(top = twelveDp, end = eightDp)
) {
itemsIndexed(
items = featureUsersLazyPagingItems,
key = { _, featuredPerson ->
featuredPerson.uid
}
) { _, featuredUser ->
featuredUser?.let {
//Daw the age suggested People
DrawSuggestedPerson(featuredUser.toPersonUser(),) {
homeViewModel.deleteFeaturedUserFromLocalDb(featuredUser.uid)
}
}
}
featureUsersLazyPagingItems.apply {
when {
loadState.refresh is LoadState.Loading -> {
item {
ShowLazyColumnIsLoadingProgressBar()
}
}
loadState.append is LoadState.Loading -> {
item {
ShowLazyColumnIsLoadingProgressBar()
}
}
loadState.refresh is LoadState.Error -> {
val e = featureUsersLazyPagingItems.loadState.refresh as LoadState.Error
item {
LazyColumnErrorView(
message = e.error.localizedMessage!!,
onClickRetry = { retry() }
)
}
}
loadState.append is LoadState.Error -> {
val e = featureUsersLazyPagingItems.loadState.append as
LoadState.Error
item {
LazyColumnErrorView(
message = e.error.localizedMessage!!,
onClickRetry = { retry() }
)
}
}
}
}
So the LazyRow displays the same set of 30 or so items but only 3- 4 items are visible on screen, for a bit of variety, I would like the items to be re-arranged so that the user can see different items on the screen. Is there a way to achieve this?
You can shuffle your list inside remember, by doing this you're sure that during one view appearance your order will be the same, and it'll be shuffled on the next view appearance. I'm passing featureUsersLazyPagingItems as a key, so if featureUsersLazyPagingItems changes shuffledItems will be recalculated.
val shuffledItems = remember(featureUsersLazyPagingItems) {
featureUsersLazyPagingItems.shuffled()
}
The only problem of remember is that it'll be reset on screen rotation. Not sure if you need that, and if you wanna save state after rotation, you need to use rememberSaveable. As it can only store simple types, which your class isn't, you can store indices instead, like this:
val shuffledItemIndices = rememberSaveable(featureUsersLazyPagingItems) {
featureUsersLazyPagingItems.indices.shuffled()
}
val shuffledItems = remember(featureUsersLazyPagingItems, shuffledItemIndices) {
featureUsersLazyPagingItems.indices
.map(featureUsersLazyPagingItems::get)
}
I suggest you checkout out documentation for details of how state works in compose.

How to escape (to initial calling place) from a recursive function in swift?

var currentCount = 0
let totalCount = 100
func myEscapingRecursiveFunction(_ json: String, done: #escaping (Bool) -> Void) {
currentCount+=1
if currentCount == totalCount {
done(true)
}
else {
myEscapingRecursiveFunction("xyz") { done in
// what should I do here????
}
}
Calling
// (Initially called here)
myEscapingRecursiveFunction("xyz") { done in
if done {
print("completed") // I want to get response here after the recursion is finished
}
}
I want my function to escape only when the current count is equal to total count, otherwise it should recurse, the problem is that I want to get response in place where it was initially called, but it will always execute the completion handler code where it was last called. here:
You just need to pass the same escaping block to your recurse function.
so call your function like this.
myEscapingRecursiveFunction("xyz", done: done)

How to remove duplicate object in array?

I have a VC where I fetch data for only the 1st object in an array of objects. so I only fetch arrayOfObjects[0] then when I enter a second VC I need to fetch all the other data associated with the other objects in that same array. But then I have a problem where I end up fetching that first bit of data I already had again. So my array would look like, data1, data1, data2, data3 ... which is not what I want of course.
Currently what I had tried to fix this issue, was to do the following: MainObject?.arrayOfSubObjects.remove(at: 0), this however means that on the first go it works well, but every time I go back to the preceding VC and then back I subtract one of the objects that I want to be there. So I end up with: data2, data3 ...
So my question is how can I remove that extra object from the beginning, but not delete anything after its been deleted?
Some things i have tried:
if selectedPost?.media[0].videoURL != nil {
if selectedPost?.media[0].videoURL == selectedPost?.media[1].videoURL {
selectedPost?.media.remove(at: 0)
} else {
print("NO!!!!!! they are not the same ")
}
} else if selectedPost?.media[0].image != nil {
if selectedPost?.media[0].image == selectedPost?.media[1].image {
selectedPost?.media.remove(at: 0)
} else {
print("NO!!! they are not the same ")
}
}
This however does not do anything, it always ends up going into the else. I have also tried stuff like setting number schemes, but this failed because the VC kept reloading
You can try to do it like this:
guard let selectedPost = selectedPost else { return }
if selectedPost.media.contains(where: {$0.image == image}) { return } // Here the $0.image should be replaced with $0.mediaURL == mediaURL for the videos or however you videoURL is called in Media
selectedPost.media.append(Media(image: image, timeStamp: Double(timeStamp)))
self.tableView.reloadData()
Try conforming Hashable in you Media class:
class Media : Hashable {
var hashValue : Int {
return image.hashValue
}
var image = UIImage()
// .....
static func == (lhs: Media, rhs: Media) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
Then you can compare two media objects with ==, So you can do something similar to the top part of this answer. Good luck

generic tap function for XCUIApplication

We are trying to migrate from UIAutomation to XCUITests.
For the UIAutomation we came up with a handy 'tapOnName' function which just crawled thru a whole sub element tree and tapped on the element with the first match.
function log(msg) {
UIALogger.logDebug(msg);
}
//recursive function crawling thru an elements hierarchy
//and tapping on the first match of accessibilityIdentifier
//or button text
function tapOnNameWithRoot(name,el) {
if (el.name()==name && el.isVisible()) {
log("tap on itt!!!")
el.tap();
return true;
}
if (el.toString()=="[object UIAButton]" && el.label()==name) {
log("tap on Button!!!")
el.tap();
return true;
}
var elements=el.elements();
if (elements===null || elements===undefined) {
log("elements null or undefined for:"+el.toString());
return false;
}
for(var i=0,len=elements.length ;i<len;i++) {
if (tapOnNameWithRoot(name,elements[i])) {
return true;
}
}
return false;
}
var win = UIATarget.localTarget().frontMostApp().mainWindow();
//for ex taps on a button with the text "pushme" in the
//main UIWindow
tapOnNameWithRoot("pushme",win);
No the question : is it possible to implement the same function using XCUIApplication ?
There is shorthand support for this function in XCTest.
For tapping the first match out of any element, you can get all elements and tap the first one:
let app = XCUIApplication()
let element = app.descendentsMatchingType(.Any)["someIdentifier"]
element.tap()
If you know what type of element it is going to be, it's better to filter by that type first:
let app = XCUIApplication()
let element = app.buttons["someIdentifier"]
element.tap()
Are you looking for something like this:
func tapBasedOnAccessibilityIdentifier(elementType elementType: XCUIElementQuery, accessibilityIdentifier: String) {
var isElementExist = false
for element in elementType.allElementsBoundByIndex {
if element.label == accessibilityIdentifier {
element.tap()
isElementExist = true
break
}
}
if !isElementExist {
XCTFail("Failed to find element")
}
}
where you call the method in the test like:
tapBasedOnAccessibilityIdentifier(elementType: app.staticTexts, accessibilityIdentifier: "Accessibility Identifier")
You can tweak it a little so that it cover all the requirements.

Signal that a network call inside a for-loop is done, then move onto the next item in the for loop?

How would I tell the for-loop to move on to the next item in the array in Swift?
for (key, value) in commentIds {
NetworkHelper.makeNetworkCall(key, completionHandler:{
//Tell current thread the for-loop is being called, to move on to the next item in the for loop?
}
}
I'm planning on having the for-loop in a dispatch_async thread, so it doesn't block the main thread.. Am I designing this wrong..? Should I have a flag?
edit
Flags in the main thread seem to work. Once the network call is done, flip the flag.
I would make the assumption that if the makeNetworkCall method takes a completionHandler parameter that it will be doing its work asynchronously. Given that, the for loop will call makeNetworkCall for every key in commentIds before any of them complete.
If you want to process them in series and not start the next one until the prior has finished, you will need to create an array of the keys and write some code like this:
var commentIdKeys: Array<KeyType>()?
var keyIndex: Int?
func startRequests() {
commentIdKeys = Array(commentIds.keys)
keyIndex = 0
processNextKey()
}
func processNextKey() {
guard let keys = commentIdKeys, let index = keyIndex else {
print("processNextKey() invoked without values set")
return
}
guard keyIndex < keys.count else {
commentIdKeys = nil
keyIndex = nil
print("Finished processing keys")
return
}
NetworkHelper.makeNetworkCall(key, completionHandler:{
// Do some work
self.keyIndex = ++index
self.processNextKey()
}
}

Resources