This is probably the most frustrating situation I've dealt with, and it probably has the simplest solution.
I've got this UIButton storeB that gets properly initialized during the viewDidLoad: call of my UIViewController. Before I create the button, I create 5 other buttons.
During viewDidLoad:, I run this method called setupFBConditions which determines whether my forwardB button object should have an alpha of 0.5 with userInteractionEnabled set to 0. When this is the case, the button looks and performs the way it's supposed (essentially, like it's not there).
Furthermore, during this particular animation that is performed on one of my UIView objects, I decided to set the userInteractionEnabled property of my restartB object to 0 (so that no interaction occurs during the animation. That performance is also successful.
However, when I decide to write:
storeB.userInteractionEnabled = NO;
storeB.alpha = 0.5;
at the start of the animation (with the intention to keep this state till the game finishes or restartB is tapped again), and NSLog the button object, the log says that the userInteractionEnabled property is NO and alpha is 0.5, just like it should be. However, at no point do these properties get reflected to the UI.
storeB is my not even my last view to be added to the hierarchy (although it is the last UIButton). I have no idea why these changes are not taking effect.
I'm not going to post any more code because there's nothing to post besides the two lines above. It's that apparently simple of a problem + solution.
************ UPDATE **************
Here is the log report at the end of one of my swipe gesture actions (after storeB.userInteractionEnabled = NO;):
<UIButton: 0x1585ae80; frame = (270 8; 42 42); alpha = 0.5; opaque = NO;
userInteractionEnabled = NO; layer = <CALayer: 0x15899da0>>
<UIView: 0x1592bba0; frame = (0 0; 320 568); layer = <CALayer: 0x15934ae0>>
The frame is correct, the alpha and interaction settings are correct, and the superview frame (0,0,320,568) is exactly what it's supposed to be.
*********** SECOND UPDATE **************
In case anyone finds this useful...check the _retainCount property of your UIView/UIButton and see if it looks unusually high when taking into account all the operations done to the object. My retain count was 4 when it should have been 2, so every time I changed the property (of what I thought was my first instance of storeB), it was actually only affecting the second instance (that I didn't even know existed).
Related
When I transition between view controllers, the two latest ones I have created, in the debug, I am getting a large string that I'm not quite able to get to the bottom of.
Can anyone point me in the right direction/ help me to understand this and find the problem I've made?
I have compared all of my documents/view controllers to my working/non-error ones and can't find anything obvious.
2019-02-12 18:47:20.879463+1300 Techsupport[15324:9474292] <UIView:0x7ff96154a2f0; frame = (0 0; 375 812); autoresize = W+H; tintColor =UIExtendedSRGBColorSpace 1 0.149131 0 1; gestureRecognizers = <NSArray:0x600002c474e0>; layer = <CALayer: 0x6000021d42c0>>'s window is not equal` to <Techsupport.EslViewController: 0x7ff9618fd800>'s view's window!
It's easier to read if you take out all the details about the view:
Techsupport[15324:9474292] <UIView>'s window is not equal to <Techsupport.EslViewController: 0x7ff9618fd800>'s view's window!
It's hard to know exactly what's going on without seeing some of your code, but fundamentally the view that the error is complaining about (located at 0x7ff96154a2f0) belongs to a view hierarchy in a window that's different from the one that the view controller's view is in.
Here are some things to consider:
How are each of these views created?
Do you expect to have two windows? (Most iOS apps only have one.)
What are you trying to do with the view in question?
A good way to start is to set a breakpoint at the spot where the error occurs, and then work backward until you figure out where the view in question comes from.
As #Sachin Vas said, "it looks like you have a segue which is set to trigger automatically and also programmatically in the code." he was correct, I did have a mistake where I had called the function programmatically as well as automatically. Thanks for everyone's help!
I'm wondering if I've somehow stumbled upon a bug where swipe to delete UITableViewCells don't ever deallocate when their UITableViewController does.
I've added a -dealloc method into my custom table cell, which logs out a message. When I press back on the navigation controller, all 6 messages are logged out.
If I swipe to delete one (or more), and press back, only 5 are logged. So I log out the pointer address of the cell that has been deleted, for future reference. Now when I go back and pause the execution at any point, I can enter into the lldb prompt:
po 140382950334240
<TableLeakCell: 0x7fe67852a490; baseClass = UITableViewCell; frame = (-375 176; 375 44); text = 'Chris'; hidden = YES; autoresize = W; gestureRecognizers = <NSArray: 0x7fe678530d70>; layer = <CALayer: 0x7fe67852a860>>
This should have been deallocated! The x.position of the cell is exactly -(tableView.width), and hidden=YES. As in the cell is still in the position after the animation has finished. Or perhaps it's being queued for reuse? Either way, it's there forever, and there's nothing in Apple's documentation about having to manually destroy a cell after calling deleteRowsAtIndexPaths.
Quick proof of concept project here:
https://github.com/iOSDigital/UITableViewLeak
At least using Xcode 7.2/iOS 9.2 Simulator and Xcode 7.3/iOS 9.3 Device all cells get deallocated. Only change is the order of deallocation, the deleted cell get's dealloc'd last.
Was hoping someone could help with this please? I've scanned through the forum and apple docs and can't find anything that matches my problem exactly.
I'm trying to animate a custom 'Composite' UIView derived class (with overidden drawRect) by changing a custom colour property (not one of the standard view properties like centre, alpha, backgroundColour etc), calling setNeedsDisplay and redrawing the view using drawRect over X seconds duration to produce a slow colour change from say, red to blue.
At the moment, all Composite::drawRect does internally is clear the context (the view has a default background colour set to clear) and fill the view using the colour provided. This works fine the first time it's called - the view appears on screen in the correct red colour.
My problem is that when I try to animate the view by updating the colour property, even though drawRect is being called everytime I call setNeedsDisplay and the colour being fed into the view instance is correct the view doesn't update on screen until I stop calling setNeedsDisplay (or rather, stop updating the custom view colour property). It's like every call to setNeedsDisplay pushes the view to the back of a list so it doesn't get updated on screen until it stops getting called (even though drawRect is being called).
For example - trying to change the colour from red to blue over 10 seconds, the view stays red for 10 seconds, then turns to blue in a single frame at the end of the property changing (and presumably when I stop calling setNeedsDisplay) rather than a slow fade between the two over the time duration.
Any ideas what's going on? I'm guessing I need to animate this using apple's own animation property stuff but I'd really prefer not to - I'm trying to make this cross platform if possible and I don't see why my own method shouldn't work.
The basics:
In case it matters, my composite view instance is a subview of an UIImageView. (I know imageview drawRect doesn't get called but I can't imagine this is a problem for it's subviews - after all, my Composite::drawRect is definitely being called).
I'm setting the right colour on my view instance - I've debug printed this to be sure - so the colour provided to the view goes from red to blue over however many seconds / frames.
I'm setting setNeedsDispay and drawRect is being called every time - again, debug printing confirms this.
This is happening over multiple frames and the app goes through the drawing update at the end of every frame - I.e I'm not blocking the render thread or anything - the app runs fine, it just doesn't update the view on screen even though its drawRect is being called, until I stop manipulating the property. Someone mentioned a similar problem where they were blocking the render thread in a single frame but I'm definitely not doing anything like that.
I've tried messing around with the following but they all produced the same results (i.e. view changed from red to blue in a single frame rather than a slow change over).
Updating the colour every frame but only calling setNeedsDisplay on my view every Xth frame (5, 10, 20, 30 etc)
Updating the colour every frame but not calling setNeedsDisplay unless the corresponding drawRect call from the last setNeedsDisplay has happened (i.e. set a flag to false in SetColour func, set same flag to true in drawRect, test against it when decided to call setNeedsDisplay) - same results.
setting the view bounds with ContentMode set to redraw to force an update - same results
tried calling setNeedsDisplay on the parent image view too - no change.
I'm guessing that this just isn't possible - can anyone explain why its not updating the v view onscreen even though drawRect is being called? Any ideas how I should do this? I don't think I would be able to do what I want to do if I tried animated one of the default view properties using apple's internal animation system but if I've got to use that....
Thanks!
:-)
I have tried many times to implement a D-Pad for my new maze game, but am having trouble doing so. I am doing it in the style of 4 UIButtons and if you press one, it moves another image up, down, left or right. I have tried using the quartzcore and CAAnimation, but only know limited code.
I have the methods and the buttons declared, but cannot code a working one.
I was doing:
-(IBAction)Up:(id)sender{
CGPoint origin1 = self.Player.center;
CGPoint target1 = CGPointMake(self.Player.center.x, self.Player.center.y-124);
CABasicAnimation *bounce1 = [CABasicAnimation animationWithKeyPath:#"position.y"];
bounce1.duration = 0.1;
bounce1.fromValue = [NSNumber numberWithInt:origin1.y];
bounce1.toValue = [NSNumber numberWithInt:target1.y];
[self.Player.layer addAnimation:bounce1 forKey:#"position"];
}
The ghost moves down, but bops back up immediately. I've been stumped for hours and it may be glaring me in the face, but please understand my noobishness.
In Core Animation, there are two layer hierarchies: one of model layers and one of presentation layers. Presentation layers are what you see; model layers are what you often interact with in code. This separation is valuable because it lets you create implicit animation -- e.g. set the position of a layer, and it'll animate to the new spot. (But if you assign a value to position, you want that to be the value you read back immediately thereafter, even if the animation is still in progress.)
When you use addAnimation:forKey:, you're affecting the presentation, not the model. So, during the animation, you see the Player layer moving, but that layer is "really" still where you left it. As soon as the animation ends, it's removed from the layer, so the presentation matches the model again -- you see it at its original position.
If you want the model position to change as well, you need to change it separately:
self.player.layer.position = CGPointMake(self.player.layer.position.x, target1.y);
You can either update the model immediately after adding the animation (you'll see the change after the animation completes), or use a completion block to schedule it at the end of the animation. There are subtleties to consider for either approach.
Often, though, if you just want to animate a specific change like that, especially for the main layer of a UIView, it's simpler to use the implicit animation API on UIView:
[UIView animateWithDuration:0.1 animations: ^{
self.player.center = CGPointMake(self.player.center.x, target1.y);
}];
This will both update the model value and create and run an animation for moving from the current position to the target position.
BTW: It helps to follow Cocoa code style conventions: use initial caps only for class names or other type names, and lowercase for variable/property/method names.
I'm trying to make a inputAccessoryView AND the keyboard modal for VoiceOver users so they don't get lost. Setting:
view.accessibilityViewIsModal = YES;
textField.inputAccessoryView = view;
Makes the view modal with keyboard visible but unusable - it is outside of the modal view.
Next I tried this after the keyboard has appeared:
textField.inputAccessoryView.superview.accessibilityViewIsModal = YES;
Which seems a bit out of bounds but almost worked - but the keys physical after B (N, M space, etc) were not navigable.
Next up was this:
textField.inputAccessoryView.superview.superview.accessibilityViewIsModal = YES;
and everything works just fine. That view, BTW logs as follows:
<UITextEffectsWindow: 0x17170290; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x17170710>; layer = <UIWindowLayer: 0x17170430>>
My question is this: I this a stupid thing to do? Seems like it. Is it legal? UITextEffectsWindow is private, but I'm not actually using it, just taking advantage of the fact that it's a view.
Any input or ways to work around the problem would help.
It's not illegal, but it is safe to assume it will stop working in future versions of iOS.
For example, in iOS 6, a developer could get from a cell to its tableview by calling self.superview. In iOS 7, there is now a private-classed view in between.
You may want to take a more dynamic approach, like traversing up the view hierarchy until you find a view with the correct frame, or with all of the views you need as its subviews. A similar approach for the UITableViewCell problem can be found here.