For example, I have 2 buttons Change email and Change password, and each of them call functions with Alamofire request, and responce data should reload both the UI and data scheme.
The point is that this PUT requests change not only servers's data, but generate new token and get updated user's profile.
And when pressing buttons at the same time, at the same moment touches begin and end, app crash after parsing requests.
I'm blocking another UI elements(like textfields), I was trying to block another button, but when press it together, it's not works.
So how can I prevent the same time touch? I'm not good at OperationQueue, maybe thats'the way? Is there an option to check if operation not first at the queue and kill it?
Set isExclusiveTouch of your UIButton to true in order to trigger only one button action in a specific time.
This code will get all the buttons contained in the view and set the exclusiveTouch to true:
self.view.subviewsRecursive()
.filter { $0 is UIButton }
.forEach { $0.isExclusiveTouch = true }
This problem with the UIResponder object is very usual. However, your problem description is not clear and your implementation seems not so good.
Here, to resolve this quick touch event problem:
Your solution is debouncing the action event of UIButton.
Debouncing also helps to prevent multiple executions when a user mistakenly pressed a button (or any UIResponder object) multiple times so quickly that even the UI was not blocked till then. Following article may guide you more regarding the same:
Debouncing to tackle repeating user action
Related
I am trying to add a WKLongPressGestureRecognizer to cells in a WKInterfaceTable. But it does not work. The IBActions are never fired.
Is there any trick that I'm missing? Or is this simply not supported on watchOS?
In case it's helpful... I've been battling the same and got to:
Attaching the 'Long press gesture recogniser' under 'Table' in your screenshot, rather than 'Group' and linking to an Action in the WKInterfaceController:
- (IBAction)didLongPress:(id)sender
{
if ([sender isKindOfClass:[WKLongPressGestureRecognizer class]])
{
WKLongPressGestureRecognizer * item=(WKLongPressGestureRecognizer *)sender;
CGPoint p=[item locationInObject];
NSLog(#"long press point: %f , %f. state=%d\n",p.x,p.y,[item state]);
}
}
It's not a final solution, but the action does at least get triggered. Unfortunately when triggered, it stops the didSelectRowAtIndex coming through so it's not easy to figure which row has been long-pressed. My best thought for progressing would be to use the p.y value to determine which row in the table was long-pressed on. I've been trying to figure out how to programmatically determine row heights or translate a location into an object but have so far failed, so for the moment I have given up on this functionality as I don't really want to hard-code a row-height in. But maybe it gets someone else closer to a solution, or fits a situation where row-height can be safely be hard-coded :)
Other routes I tried (and failed), but might be a starting point for others (or save some time):
trying to cancel the long press, so I still get the row-select come through (but I could have recorded we have a long press, so can act accordingly). Unfortunately I couldn't see how to do this. I tried [item setEnabled:false]; but it didn't cancel the current long press. It just stopped all future long presses being recognised.
I looked up programmatically attaching gestures in case this would give greater control than using storyboard. I didn't get anywhere, and my research indicates this is only supported in iOS, not WatchOS.
Attaching a gesture as per the posted question. I too was unable to see evidence of any action code being called :(
I have a button which sends network requests. I want to ignore double taps within this button. I tried .throttle, but that didn't seem to work. So I'm trying .debounce - this indeed ignores duplicate taps, but only lets through the last event.
What I want is: On first tap, send a network request, ignore subsequent taps within 0.33 seconds.
Which RXSwift operator would help me put an event through and disable subsequent events within a time window?
let buttonPressObservable = button.rx.tap.asObservable()
buttonPressObservable.debounce(0.33, scheduler: MainScheduler.instance)
.map{/*do stuff*/}
In version 4.2 of the library, throttle has a parameter latest that is set to true by default. If you set that to false, I think it will give you the behavior you want.
I have a Page View Controller that's implemented in 3 files. One of them, the ModelController.m implements "generateData" method, which basically just builds and formats all the pages for this Page View Controller. Inside this method, the first thing I do is I create a Progress Bar popup with "Cancel" button. Then, inside the while() loop, I keep building the pages and at the same time, every 10th page, I update the progress bar for the user to see that the application is still generating the output.
Once the "generateData" method completes, i.e. builds all the pages (and there may be over 1,000 or even 10,000 pages depending on user input), it returns "self" to a method inside RootViewController.m, which in turn passes that generated data in "dataObject" to "viewWillAppear" in DataViewController.m, which finally displays pages in that object to the user.
It all works great, except the "Cancel" button. Because "generateData" method runs on the main thread, it blocks and the "Cancel" button becomes totally unresponsive. By "blocks" I of course mean it takes all CPU cycles, not allowing anyting else to execute, and it may take over a minute to generate 10,000 pages so I really want to allow the user to cancel the operation.
I tried to create a separate thread for the Progress Bar popup which contains Cancel button, but that won't work because all UI operations need to be performed on the application's main thread.
What almost seems to work, is when I put the "generateData" method on a separate thread and keep the Progress Bar on the main thread. This would work just fine, except that now "generateData" is put on another thread to execute in the background and returns immediately, hence returning empty "self" or rather empty "dataObject", causing a crash because there is nothing in that object yet to display.
So how can I check if the "generateData" thread is done, and "return self" ONLY when it's done? I can't really have some BOOL true/false variable and do it in a loop, because that loop on the main thread would be again blocking the "Cancel" button.
Or, alternatively, what is the correct way to implement the "Cancel" button on a lengthy method in iOS? Maybe I'm doing it all wrong, but for the life of me I can't find the right recipe for this.
Thank you in advance for the help, the code is rather extensive and that's why I didn't include any, but I hope my description gives you a good idea of what's going on. I can provide code if that would help.
The correct way to do this is to load the data asynchronously (on a background thread) and update the main (UI) thread to update the progress bar, etc... But you probably don't need a progress bar since you can probably load those pages faster than a user can flip them, so load 100 and let the user play while you continue to load the next 99,900... Except those may not be the exact numbers you should use....
If you continue to use the progress view and cancel button, then you would cancel the background thread when the user presses "Cancel", which would respond since your data generation is on a background thread...
Look into either Grand Central Dispatch or NSInvocationOperations
Here's a good tutorial by Ray Wenderlich to get you started.
I am detecting whether the user has accepted the request to use location services in my app, I have a toggle switch in the UI that is dependent on this acceptance. The first time they toggle the switch (on) the request to use location is triggered. I want to know which button they press in that alert. (accept or decline) Right now I'm just toggling it off and making the user press it again (then detect which option they picked).
It is kind of sloppy that way, so I'd like to know if there is a way to detect this specific alert or can't that be done since it is triggered by the OS, not the application? I haven't tried it yet, but was thinking I could use the UIAlertView delegate methods for just generic button presses, but was hoping for something more specific.
UPDATE
I was able to get this working by just registering a notification when I trigger the location request (and the authorization prompt is shown). The application is placed in an inactive state (much like pulling down the notification bar). I just trigger a notification when the application becomes active and I'm able to just query the authorization status there and update my UI. I hope this helps anyone else down the line if they want to handle the authorization status on the fly.
There is no way to intercept the alert. There is, however, a method on CLLocationManagerDelegate method called didChangeAuthorizationStatus. That's probably the closest you can get to intercepting the alert.
There is no way to know explicitly which button the user selects since, as you've said, this alert comes from the OS. You can however, find out if location services has been enabled for your app, and know that way. Use a method such as this:
-(BOOL)locationServicesIsEnabled
{
if (![CLLocationManager locationServicesEnabled] || ![CLLocationManager authorizationStatus])
return NO;
return YES;
}
I am working on a large (>30k lines) event-driven app. I have a sequence of inputs that produces a bug. What I want to do is to break as soon as the final input enters my code.
Is there a general way to do that?
I understand that for any specific sequence of inputs, I can find out where that last input is going to enter my code, then set a breakpoint there. What I would like to do is take out the step of "find out where that last input enters my code." In other words, I am running the app in the simulator, and I want to set a flag somewhere that says "break the next time you are going to enter non-system Objective C code." Then I send the event that causes the problem.
I understand what you are asking, but have you tried using an Exception Breakpoint? This will basically act like an auto-inserted breakpoint on the piece of code that throws the exception. If that doesn't work for you, try a symbolic breakpoint
If you want to intercept UI events, you can try subclassing UIWindow and overriding its sendEvent: method, then setting this class as the class of the UIWindow object in your main XIB file. sendEvent: will be called each time the user generates a touch event. Unfortunately, at this point you cannot yet know which UI object will finally consume the event (read: which event handler code will be ultimately called) since that depends on the actual state of the responder chain. But anyway, you can use this method to inject events into the system.