Allocation in ARC - ios

i am facing one problem i.e in ARC enable project if add buttons to scroll view by adjusting its y position,then allocation is showing that 50%. But in ARC it should not display right. That for loop may iterate 15000 times . And i got unbounded memory growth,i observed that progress bar getting lazy when the count is increasing.Example code is
static int i;
for(;i<15000;i++)
{
UIButton *but = [UIButton buttonWithType:UIButtonTypeCustom];
but.frame = CGRectMake(50, j, 60, 30);
j = j+30;
[_scroll addSubview:but];
}
here i am getting 50% allocation.
but.frame=CGRectMake(50, j, 60, 30);

As mentioned in the comments, the setup is not quite right for your context.
Your app slowed down because it was using so much memory due to the instantiation of 15000 UIButton objects.
You said that you need to have so many instances, because you are doing some sort of list for contacts. This is exactly the use case for UITableView or UITableViewController (it's the same UI control that Apple uses in its own preinstalled apps).
It allows you to reuse the cell objects (instances of class UITableViewCell) instead of creating a whole new object for every contact you want to display.
You will have to implement the UITableViewDelegate and UITableViewDataSource protocols for the setup to work. These are not too trivial at first sight, but you'll get acquainted to the underlying mechanism rather quickly once you start to take off. I'd recommend you to start with a simple tutorial and then move on to your particular case from there.

Do not reinvent the wheel !
As the previous speakers already pointed out you should use a UITableView.
But you do not have to reinvent the wheel. There are a lot of implementations out there which face exactly this problem.
Here you can find a good implementation which already uses a UITableView (1: Objective-C, 2:Swift).
SSMessagesViewController
Acani Chats
What it basically does is:
Use a custom UIView to display the "bubbles"
Use this custom UIView to display in a custom UITableViewCell
Use this custom UITableViewCell to be displayed in a UITableView which manages to get a high perfomance for your task

Related

My ViewController is getting really big due to UI coding

Currently I am working on a project which got all the task done in a singe viewController. As there are so many elements on the viewController I choose to do the UI with coding, like this:
let myButton: UIButton = {
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(openFunction), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
As there are so many button, view, texifield, label etc along with all their constraints written with code, my viewController class getting bigger and bigger. How can I keep all the UI code in separate file and integrate in on my viewController ? I don't know there might be really easy way to do that but I am actually struggling. Any suggestion would be really helpful.
Welcome to the world of design patterns and code architecture. They are various ways to accomplish what you are after. It's a good sign you are able to identify this problem early.
You can start looks at MVVM, VIPER, ReSwift among others. Research which fits your the requirements of your app.
Suggestions for Reducing UI Code in view controller:
In terms of reducing just the UI Code growing in the view controller, I suggest start creating subclasses of common elements and keey your code DRY. For instance, if a UIButton with same fonts and borders etc are being created many times then look at creating a subclass for it and move the configurations inside this subclass.
You can also create subview of logical elements on the screen, example you have a header with buttons and labels then move it into a subclass and start using this subclass from here on. This should improve your code readability and reuse.
You can also reduce a lot of the autlayout code by create extensions of commons layouts like pinning to all corners etc this way the repetition of boilerplate auto layout code is much less.
An alternative to what carbonr has proposed is to leverage Interface Builder. With Interface Builder, you can create one or more StoryBoards and separate UI elements and constraints from the controller that contains your code. Obviously, if you are unfamiliar with Interface Builder there would be a learning curve.
A specific answer to your specific code would be to create a convenience initializer in an extension to UIButton.
extension UIButton {
convenience init(_ target:Any, _ action:Selector) {
self.init(CGRect.zero)
self.addTarget(target, action:action)
self.translatesAutoresizingMaskIntoConstraints = false
}
}
Right there you are probably cutting back on things in your VC.
Next, consider moving this - and all - UI code out of your VC file and into other files. I typically move my extensions/subclasses into as many files as needed. (The build may take longer but the final binary should be the same size.) For large projects, this helps make things manageable.
At the same time consider making an extension to your VC specifically for auto layout (which I see you are using because you are setting your UIButton auto resizing mask). As long as you are declaring your objects in the main subclassed VC, this removes the "verbose" nature of auto layout into it's own file.
For multi-developer projects and/or true "reusable" code, a final thing you can do is move code into a Framework target.

Add a UIView over the top of UITableViewController in Swift

I currently use a UITableViewController (PFQueryTableViewController), I would like to display a UIView over the top of the TableView.
Ideally I'd like to do this in the storyboard, so I can easily add additional Labels/buttons to it. However, I can't seem to figure out how or if you can do it in storyboard. Is that right?
I have tried it programmatically. I first created the variable at the top:
var filterLabelView:UIView = UIView()
I then added the following in ViewDidLoad :
filterLabelView.frame = CGRect(x: self.view.frame.width/2, y: self.view.frame.height/2, width: self.view.frame.width, height: 40)
filterLabelView.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2)
filterLabelView.backgroundColor = UIColor.redColor()
self.view.addSubview(filterLabelView) // See below
I also tried:
self.view.insertSubview(filterLabelView, aboveSubview: tableView)
This creates the red UIView, but it seems to be embedded to the tableview, as when I scroll up and down, the View moves with it.
What I want to create
Ideally, I want the view to sit at the bottom of the screen, and not move when the user scrolls. An example screenshot of how I want it look is below:
I have read that the best way is to use a UIViewController with a UITableView inside it, but I'd rather not take that approach seeing how much my app is already built up.
Can anyone help me create this look? Thanks in advance
You have to derive from UIViewController to get full layout control.
Then simply add a UITableView instance in Storyboard. Constrain it normally, edge-flush, top-flush, and have customView.top = tableView.bottom. Make a normal outlet to your controller.
You just need to remember to make your custom UIViewController adopt the usual dataSource and delegate protocols, as well as assigning itself as those roles to the properties of the UITableView on initialization (usually viewDidLoad()).
There's one more finesse related to clearing the selected cell when on viewDidAppear(), but there's nothing else special about a UITableViewController -- it's just a UIViewController with a built-in tableView property and automatically assigned delegates and a very inflexible layout.
ADDENDUM based on comment about how to get around this: It's sort of like asking if there is any way to make a screwdriver drive a nail into wood. Just use the right tool. The top-level view property of a UITableViewController is the UITableView itself. See below, a stock UITableViewController with nothing else, zero code, in layout debug mode.
This means the entire tree of views is embedded in a scrolled entity, so all subviews will scroll with it.
It really shouldn't be that big a deal to re-do this one VC in Storyboard. After all, your rendering code in cellForRowAtIndexPath and your dataSource and delegate generally, don't change at all.
ADDENDUM 2:
Not knowing Parse intimately, this may not be possible. (!! Thanks, Parse.) If Parse doesn't supply you with a separable PFQueryTableView that you can embed yourself, the following workaround may be possible, but you'll need to understand the Objective-C code:
https://www.parse.com/questions/pfquery-tableview-for-uiviewcontroller

Inject custom class into subclass inheritance tree in Objective-C

I think of myself as an experienced Objective-C programmer. I do apps for a living, and use the language features to it's fullest. That includes using the runtime for varies just-in-time changes to existing frameworks. Stuff like method swizzling and dynamic subclassing really shows how this language is so much more versatile than it's other object oriented C counterpart.
But lately I've been having some thoughts about an old feature, that I still find myself in need of using from time to time, but has been deprecated for some time now. It's a replacement for the old class_setSuperClass.
I often find myself subclassing UIKit classes in order to extend them or just change their behaviour slightly. One example I came across recently was an UIScrollView subclass, that made some conditions to the panGestureRecognizer. I did that by subclassing UIScrollView and then implementing the gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:.
This had to be done this way, because you're not allowed to change the delegate of a scroll view's pan gesture recogniser (it will throw a runtime exception), and you cannot create your own custom UIScrollView panGestureRecognizer.
Now this all worked out great. I changed all usages of UIScrollView in my app to my newly created subclass, and everything worked as expected. But what about UITableView and UICollectionView which I also used throughout the app. What to do with those? As you know, both of these classes is inherited from UIScrollView, but not my custom subclass of UIScrollView. So I found myself ending up writing the same code multiple times for every class that existed (and was used in the app) that inherited from UIScrollView. Writing the same code multiple times is a programmers 1-2-3 no-go. But I did end up writing a custom subclass not only for UIScrollView but also for UITableView and UICollectionView.
Now in the old days with the class_setSuperClass you were able to "swizzle" the superclass of an already prepackaged class like UITableView. You basically just said class_setSuperClass([UITableView class], [MyScrollView class]), and everything worked out (well almost) fine. Now you had injected your own class in between UITableView and UIScrollView. So every time you did [[UITableView alloc] init] it would have the features of MyScrollView because it inherited directly from it.
Now class_setSuperClass was deprecated in iOS 2.0! Since that we could do some swizzling and hacking with the object's isa pointer. Now that has been deprecated too.
So my question is really simple. How would you approach this?
If you want to globally change a class's behavior, rather than play with class identities, the direct approach would just be to replace the method you want replaced. The runtime still allows this, with class_replaceMethod(). That seems like the simplest way to accomplish what you want here.

Subclassing vs Category with Interface Builder

I have read multiple times that we should not subclass a component (a UIButton for example) :
Why shouldn't I subclass a UIButton?
Subclassing a UIButton
The problem is when I use Interface Builder.
For example, I have a button with a precise appearance in a lot of my views. I can set them each time with IB (it's painful), or I can use a custom class to factorize the custom behavior and appearance.
It seems a bit contradictory to me that the only way to simplify the process with IB is to do it the way that everybody recommends against.
Is there a better solution ? Can I use a category with IB ?
Thanks.
You might be able to use the UIView appearance proxy. I don't know what all you're doing to your buttons but this might help:
Put this is your AppDelegate file in the application:didFinishLaunchingWithOptions: method
if([UIButton conformsToProtocol:#protocol(UIAppearanceContainer)]){
[[UIButton appearance] setBackgroundImage:[UIImage imageNamed:#"YourImage"] forState:UIControlStateNormal];
//modify any other UIButton properties you want to set globally
}
The second link you provided was pretty clear, and this is pretty much what apple itself states, subclass, but never mess with the internal structure.
Best example is iOS 7, now things are completely different and, for example, an application I'm maintaining had a subclassed UIControl, and now it has trouble running on the new iOS, simply because, it was built with assumptions on how the internal structure works (iterating the internal subviews replacing some things). You might not get your app rejected, but it will be a pain in the a** to maintain.
As a rule of thumb, anything you can do to an UIButton from the outside, something like this:
[myButton setBackgroundImage:... forState:...];
[myButton setTextColor:... forState:...];
myButton.titleLabel.font = ...
You can move it to the inside of a custom subclass method:
+ (UIButton*)fancyPantsButton
{
UIButton *button = [UIButton butonWithType:UIButtonTypeCustom];
[myButton setBackgroundImage:... forState:...];
[myButton setTextColor:... forState:...];
myButton.titleLabel.font = ...
return button;
}
You can also do this on init or awakeFromNib without problems (and I usually prefer the later).
UIAppearence is also an option, as was suggested by user hw731. Whatever floats your boat, really.
As for the second question, nib files pretty much create instance a class and then fill-in the things it stores using setValue:forKey: when loading (that's why you get an error like "class is not key-value compliant for something" when you screw up a nib), so if something is categorised when the nib is being loaded, then yes, nibs respect categories, as its simply using initWithCoder.. and then filling in the gaps.
And, by the same token, the nib file won't be able to fill-in custom properties, since it doesn't know about them, unless you explicitly add them on the "User Defined Runtime Attributes" in IB (iOS 5 onwards).
Another technique for nibs, is using
#property (strong) IBOutletCollection(UIButton) NSArray *buttons;
And then iterating and customising buttons accordingly (be it via a subclass, category, local method, ...). This method is really helpful if you want just a handful of custom buttons, but not enough to warrant using a subclass.
I don't see any reason that you shouldn't subclass UIButton, especially for your purpose of making configuration with IB easier. Neither of the links you provided explain why you shouldn't subclass, so their assertions don't seem reliable. On the other hand, the presence of UIButtonTypeCustom in UIButton.h gives the impression that the framework authors planned for UIButton subclasses.

iOS Design Pattern memory management with delegate and parent object

Im struggling to solve in a very clean way a problematic involving memory overload (management).
Im having a serie of view that include other views, in my project I have a situation like this:
MainView
|_PageView
|_CustomButton
soo far soo good, easy as a cake. CustomButton have a delegate (protocol) in it for some reasons, so we have in PageView a "for cycle" that creates N CustomButtons, set the delegate as self in PageView (PageVew extend CustomButtonDelegate) and release the buttons afer attaching them like
{
CustomButton *customButton_ = [[CustomButton alloc] initWithFrame:CGRectMake(100.0,50+(i*55.0),200.0);
customButton.delegate = self;
[self addSubView:customButton_];
[customButton_ release];
}
soo far soo good again. Button will be press, PageView get the protocol method, do some code and voilĂ , done. One problem is that at one point, MainView must remove PageView, so In a method I call
[pageView_ removeFromSuperview];
[pageView release], pageView_ = nil;
pageView_ = [PageView alloc] initWithFrame.....];
and I recreate the object with other data to display.
I noticed that PageView never gets release and removed from the memory because its retainCount is exactly how many CustomButton I created inside PageView and assign the delegate to self plus one of course. My question is, what is the cleanest way to remove safely all the objects and be able to remove PageView too, free the memory (because Im loading a quite large amount of data to display in it) ?
Right now i'm doing:
Create in PageView a NSMutableArray, that I CustomButton the objects in
it, and before to remove PageView, I cycle it and set the delegate = nil and then release
each object, after I release the NSMutableArray (called "holder").
But the problem is that if I want to add more objects of different types with other protocols, adding to this array, can lead to other problems of retaining the objects.
Where do I lack guys, knowledge so I need to study more (quite sure I can say) or do I need to approach with another OOD?
Thank you guys, im going overload with this problem and my brain is stuck in a close road. :)
Looks like your CustomButton's delegate is a retain property of CustomButton. Delegate should be an assign property, not retain nor copy. See here.

Resources