Lately I've been running into some subtle layout issues in my iOS app. For example displaying a viewController from one part of the app causes the layout of some subviews to be altered (the z-axis ordering changes). Another subtle issue is the navigation bar flickering slightly.
What are some techniques for debugging these issues?
I'm especially interested in printing/logging properties of objects. For example I'd like to just dump/print/log all properties of the viewController referenced above to see exactly what changes. Then perhaps one can use symbolic breakpoints to pin-point the cause.
Check out DCIntrospect. It's a tool that can be very helpful for looking at view's info conveniently.
You can use KVO to observe frames changing, so you know what changes when, from and to what values. You can even use it to fix properties to some contant value. (See Prevent indentation of UITableViewCell (contentView) while editing)
You can use reflection to loop through all properties of an object. I don't know how such a broad approach would help you, but it is possible. (See Loop through all object properties at runtime)
Another technique to use is to subclass a UIView with override methods for re-positioning a view, or other aspects - then you can set breakpoints or log when the frame changes, or other attributes.
To use the UIView debugging class you can just change the type of a View in InterfaceBuilder to be your custom view type instead of UIView.
Use iOS App layout Debugging tool
revealapp.com
Just integrate revealapp SDK in your app and work as firebug
Related
This question is for both cocoa and cocoa touch. But I'll write an example just for cocoa.
As I understood, I can setNeedsLayout to YES multiple times in a cycle and -layout will be called just once. But are there any other benefits of laying out subviews in -layout method?
Explanation / example: At the moment I'm laying out my subviews in custom viewController (that has default NSView) every time I call custom redraw method. And I call redraw method only when user changes some properties so I really want to relayout subviews.
There are plenty of external circumstances not under your direct control that might cause the system to want to lay out your views. For example, device rotation or incoming calls on iOS, or window resizing on OS X. If you have your layout logic in the standard places, then your code accommodates these without any additional effort, and in the places your internal state changes, you can request such a layout explicitly.
To turn your question around: is there a significant benefit to not doing your layout in the standard way? Do you believe that this will be a performance issue? Have you measured it to see whether it is actually a performance issue?
I have a custom graphic that is to be displayed to a user when an event occurs. The graphic needs to be displayed on whichever viewController is currently being displayed to the user.
The way i have programmed it so far is by adding to ALL viewcontrtollers:
1) the .h file for the custom graphic class
2) an observer for the NSNotification event that is raised
3) the method which actually draws the graphic.
This doesnt feel like a very efficient way of doing things and i was wondering if anyone has a better way of doing things?
To me it sounds like you've done it in a fairly sane way. The only other way I can think is to just add the graphic to the window which would then overlay on the current view controller and you'd only need to have one object listening for the notification. You could use the app delegate for instance. But then you would have to worry about rotation of the screen yourself when adding the graphic over the top.
What you are doing is correct .. The only thing you can improve is to mauve the drawing graphics part to the custom graphic class.. (if you are not already doing so...
just Make a UIViewController variable as a member variable to the graphics class..and then set it up to the current view displaying..after you receive the notifications..and the class will itself draw the code based on the ViewController you set it up to
The reason it doesn't feel efficient is that you're duplicating a lot of code. That's more work at the outset, and it creates a maintenance headache. You should be taking advantage of the inheritance that's built into object oriented languages, including Objective-C.
If you want all your view controllers to share some behavior, then implement that behavior in a common superclass. Derive all your other view controllers from that superclass, and they'll all automatically get the desired behavior. Your superclass's initializer can take care of registering the view controller for the notification(s) that you care about, and -dealloc can unregister it. This way, you don't have to clutter up each view controller with the same repeated code, and if you want to change the code you only have to do it in one place.
I have a general question for Xcode programming and the usage of the Xcode tools.
I am quite new (4 months) in iOS development and I almost never used the Interface Builder for my purposes. I always created instances programatically. My question is basically if you think i should get used to work with IB or should/can i proceed like i do now?
If you are fine with defining your UI programmatically, then I do not see any issues with that.
Interface Builder allows you to "graphically" define your interface, and this can be an invaluable tool for playing with your UI prototypes, but apart from that there is nothing that you can do in IB that you cannot do programmatically.
In my case, I see that it depends on the kind of UI that I design. When I need a pretty basic UI, the IB is unbeatable for me. On the other hand, when my UI tries to be a bit custom, then I prefer doing everything programmatically.
An interesting point is that you could use IB to design your UI, deciding on sizes and positions of your elements, and the create it programmatically.
Yes you should use IB, basically xcode having IB for ease of development, no need to setting controlls by using coordinates and each time see their visibility by running the app.
just drag and drop and at the time of making the views, you can see hows your screen going to look.
Also using IB is not a typical task so,start development using IB.
At a great number of requests from people using older iOS hardware, I'm currently refactoring and optimizing my app so it will work on iOS 3. That being said I've got a glitch with my UITabBar that I can replicate on all of the iPhone 3G units I've tested it on.
The glitch appears to have been fixed in iOS 4, but I was wondering if before that time, anyone else had this glitch as well and had figured out a (relatively elegant) workaround for it.
The problem is what you can see below; when a memory warning occurs and all of the views offscreen are released, when I bring a view controller with a tab bar back on screen, all of the UITabBarItems that are supposed to be in it are gone. As far as I can see, they're not being drawn at all; ie tapping the tab bar has no effect. After setting breakpoints and examining the UITabBar and its items in memory, they're all still there (ie not getting released), just that they're not getting redrawn when the UITabBar is re-created in the controller loadView method.
My app works similar to the official Twitter app in that I implemented my own version of UITabBarController so I could control the integration of it with a parent UINavigationController properly. I set it up as closely as possible to the original UITabBarController class though, with all of the child view controllers handling their own respective UITabBarItems and initializing them inside the class' init methods. Once the child view controllers are passed to my TabController object via an accessor method, the tabBarItems are accessed and added to the UITabBar view.
Has anyone seen this behaviour before and know of a way I can fix it? I'm hoping there's a really simple fix for this since it already works in iOS 4, so I don't want to hack it up too badly.
Thanks a lot!
After a bit of research, I think I found a solution to this. It's not the most elegant solution I was after, but it definitely works.
I'm guessing after a memory warning is triggered, something is happening to the UITabBarItem objects that basically renders them corrupt. I tried a lot of things (flushing out the UITabBar, re-creating the controllers array etc), but nothing worked.
I finally discovered that if you completely destroy the UITabBarItems and allocate new ones in their place, then those ones will work. :)
So my final solution to this was to add an extra condition in the viewDidLoad method of my controller that if the detected system was iOS 3, and there was already an array of UITabBarItems, it would go through each one, copy out all of the properties needed, destroy it, allocate a new one and then copy the old properties over to the new one.
I'm still going to keep an eye out for a better solution (I think there's a bit of overhead in this method), but thankfully at this stage, iOS 3 legacy support is becoming less and less of an issue. :)
MVC/OOP design patterns say you don't set a property, per se, you ask an object to set its property. Similarly, in Cocoa you don't tell an object when to draw itself. Your object's code has detailed HOW it will draw itself so we trust the frameworks to decide when (for the most part) it should draw.
But, when it comes to animation in Cocoa (specifically Cocoa-Touch) it seems that we now must take control of when the object draws itself from within the objects view controller. I can't send a message to a UIView subclass asking it to change some value and then leave it alone knowing it will slowly (duration = X) animate itself to a new position, alpha, rotation, etc. depending on the property changes. Or can I?
Basically, I'm looking for a way to set the property and then walk away. Instead, it seems, I need to wrap the code that calls the object asking it to change its property with an animation block of some sort "[UIView beginAnimations:nil context:NULL]; ... [UIView commitAnimations];"
I'm ending up with lots and lots of animation blocks in my view controllers and none in my view objects...I guess I'm just looking for someone to verify that this is how things are done and I'm not overlooking something. I haven't gotten much farther than the UIView animations within Cocoa-Touch, so maybe that's my problem and it's time to dig deeper?!?
You are correct that UIView does not animate its property changes by default the way CALayer does, but I don't think this indicates a break in MVC. It is appropriate for a Controller to instruct a View in how it should transform. That is the role of a Controller class as surely as it is appropriate for the Controller to know the correct frame for the View and even manage layout. I agree that it's a little weird that you call -beginAnimations:context: on the UIView class rather than on an instance, but in practice it does actually work much better that way since you may want to animate many views together.
That said, if you had a UIView subclass that managed the layout of its subviews, there would be nothing wrong with allowing that UIView to manage the animation rather than relying on a UIViewController to do it. So this is something that could go either place, but in practice it generally goes in the Controller as you've discovered.
I am using "MVC" here in the typical Cocoa sense. You're correct that this might not be appropriate in a SmallTalk program, but then SmallTalk Controllers have a much more limited role (management of user input events). Cocoa significantly expands the role of Controllers in MVC and I think it's an improvement, even if it means there are now some functions that could go in either the Controller or the View (and this is one of them).