Im doing an awful lot of work at the moment with AVMutableVideoCompositions, and AVAssetExportSessions. When exporting a video using the latter, its clear that you can affect the size of the mixed video enormously depending on the preset that you use. For a typical video of around 2 minutes in length, the exported asset can range from 5MB to 400MB in size depending on that setting. So it would be useful to have an idea of just how big an export might be, right?
To that end, I did some investigation and exported lots of different sizes and varieties of videos. I ended up with a very consistent ratio between the duration of the video composition, the export setting, and the resultant size in MB of the exported video.
The one really useful thing about this is - you can work out beforehand, whether or not the user is going to run out of disc space when doing an export session.
So the following method will give you an expected size in MB of an exported video composition, based on the supplied bits of info - duration and export session preset. Its fairly self explanatory, but its been pretty accurate so far. Hope it is of use to someone :
Tuesday, April 26, 2016
Wednesday, April 20, 2016
Adding an NSArray in Coredata
Just discovered how to add an NSArray property to Coredata. I know I know, an NSSet is just fine and does everything you need, and you can convert it to NSArray if you need to. But I just wanted to try this - I had a situation where I didnt need a whole new managed object class, I just wanted to store an array of NSNumbers. Heres what you do :
First, add your property to the data model as usual, and make it a 'transformable' property (in my case the property is called actionRules) :
Then add the normal attribute to your coredata managed object header file (and here you can actually refer to it as an array) :
And add the @dynamic to the main file :
Then some slightly more weird stuff. You add an entirely separate @interface to the same header file, using the name of the new property, and setting it to NSValueTransformer (you literally put this after the @end of the normal interface) :
Finally, add this entirely new @implementation in the main file. Before or after the other normal implementation is fine (obviously you need to change the 'ActionRules' for the name of your array) :
And thats it - you have an NSArray that you can use throughout your application as usual. Obviously its not mutable, so to add properties, create a mutableCopy of it, change it as required, then set the property as this mutableArray. Still, its quite handy I find, and theres the additional bonus of quickly organised indexing.
First, add your property to the data model as usual, and make it a 'transformable' property (in my case the property is called actionRules) :
Then add the normal attribute to your coredata managed object header file (and here you can actually refer to it as an array) :
And add the @dynamic to the main file :
Then some slightly more weird stuff. You add an entirely separate @interface to the same header file, using the name of the new property, and setting it to NSValueTransformer (you literally put this after the @end of the normal interface) :
Finally, add this entirely new @implementation in the main file. Before or after the other normal implementation is fine (obviously you need to change the 'ActionRules' for the name of your array) :
And thats it - you have an NSArray that you can use throughout your application as usual. Obviously its not mutable, so to add properties, create a mutableCopy of it, change it as required, then set the property as this mutableArray. Still, its quite handy I find, and theres the additional bonus of quickly organised indexing.
Tuesday, April 19, 2016
UIButton with animating colours - new public repo
I recently needed a flashing UIButton, specifically for a record button for a video recorder. Theres a nice easy way to do animation of such things using UIView, eg :
Unfortunately, with a UIButton, this causes issues. I found that the button would become slower to respond, and seem sluggish - it just doesnt seem to work well. So I had to go back to an older method of animation, using a CAAnimation on the layer of the UIButton.
As it took a little fiddling to get this right, I thought I would share the class in a github repo. Its here :
https://github.com/lukecsmith/LSAnimatingColourButton
And it now uses a CAAnimation that looks like this :
Any feedback or improvement requests welcome.
Unfortunately, with a UIButton, this causes issues. I found that the button would become slower to respond, and seem sluggish - it just doesnt seem to work well. So I had to go back to an older method of animation, using a CAAnimation on the layer of the UIButton.
As it took a little fiddling to get this right, I thought I would share the class in a github repo. Its here :
https://github.com/lukecsmith/LSAnimatingColourButton
And it now uses a CAAnimation that looks like this :
Any feedback or improvement requests welcome.
Monday, April 18, 2016
iOS UITableview - improving performance with AutomaticDimension
A significant improvement was made to UITableview and the process of calculated cell heights with autolayout, in iOS8. With the introduction of using AutomaticDimension for row height, you can now use proper autolayout for each cell, and you can have all sorts of dynamic stuff happening to the height of a cell, and the UITableView responds as you would hope.
There are various things to do to make this work, but this post is not about that, and you will find plenty of others that cover that well.
This is about the performance of your tableview, while using this technique. Because I was finding my performance was not great - and I didn't know why.
The great advantage of a UITableView of course, is that only what you see on the screen is being created and managed by the view. It looks like you have a big long table full of stuff, but you don't - its all being moved around with magical smoke and mirrors.
Now you would expect that only enough cells are being created at any one time - but you would be wrong. What is happening when using this particular technique, is that the value you set for estimatedRowHeight is used to calculate how many cells are required (because the UITableView cannot know, until after drawing has taken place, how high a cell actually is, and therefore, how many cells are needed to fill the visible part of the table).
So imagine your tableview is 400 px high. You have set estimatedRowHeight to 40.0. This means that the UITableView will go and prepare (400 / 40 =) 10 cells to be shown on the screen. Even if actually, after autolayout, it turned out we only needed 5 cells - still, it went and made those cells.
SO its this estimatedRowHeight value that can play a key part in the speed of your tableview. If you set it to a high value, eg in this case, 100 px, then only 4 cells are built for the view. If later the tableview realises that more cells are required, then more can be built as required.
But ultimately, it pays to be as accurate as you possibly can with this value for estimatedRowHeight. In my case, my estimate was too low, and I was building way more cells that I ever needed. So I was wasting valuable processor time, on the main thread of course, and the app was slowing down.
There are various things to do to make this work, but this post is not about that, and you will find plenty of others that cover that well.
This is about the performance of your tableview, while using this technique. Because I was finding my performance was not great - and I didn't know why.
The great advantage of a UITableView of course, is that only what you see on the screen is being created and managed by the view. It looks like you have a big long table full of stuff, but you don't - its all being moved around with magical smoke and mirrors.
Now you would expect that only enough cells are being created at any one time - but you would be wrong. What is happening when using this particular technique, is that the value you set for estimatedRowHeight is used to calculate how many cells are required (because the UITableView cannot know, until after drawing has taken place, how high a cell actually is, and therefore, how many cells are needed to fill the visible part of the table).
So imagine your tableview is 400 px high. You have set estimatedRowHeight to 40.0. This means that the UITableView will go and prepare (400 / 40 =) 10 cells to be shown on the screen. Even if actually, after autolayout, it turned out we only needed 5 cells - still, it went and made those cells.
SO its this estimatedRowHeight value that can play a key part in the speed of your tableview. If you set it to a high value, eg in this case, 100 px, then only 4 cells are built for the view. If later the tableview realises that more cells are required, then more can be built as required.
But ultimately, it pays to be as accurate as you possibly can with this value for estimatedRowHeight. In my case, my estimate was too low, and I was building way more cells that I ever needed. So I was wasting valuable processor time, on the main thread of course, and the app was slowing down.
Unresponsive UIButton, and the OTHER enable button!
Just spent a couple of hours with the simplest of issues - a UIButton that was not responding to clicks. This is almost the most frustrating kind of issue. A seemingly really simple thing, and Ive been doing iOS for 5 years now, and must have implemented 1000 UIButtons succesfully.
There are several very common reasons why a UIButton can be unresponsive, such as : userInteractionEnabled is not set to YES (either in NIB or code). Theres an invisible UIView of some kind above the button in the view hierarchy, and it is not passing on touches to objects below it. Then theres more obscure ones such as : you have implemented an animating image on the button, and it is interfering with touches. Yes - Ive had that issue too.
But Ive never before had this one. Theres another tick box, in the storyboard's UIButton panel, in the 'Control' section. Here you set the alignment of the text content - and just under there, a separate 3 booleans are titled : Selected, Enabled and Highlighted.
And my issue, after two hours of fiddling, turned out to be : that Enabled tick box must be ticked.
I have never come across that issue before. I dont actually know why this is suddenley having an effect on my UIButton. If anyone would care to enlighten me more about this (almost) hidden but essential little tick box, I am all ears!
Meanwhile, make sure this is ticked.
There are several very common reasons why a UIButton can be unresponsive, such as : userInteractionEnabled is not set to YES (either in NIB or code). Theres an invisible UIView of some kind above the button in the view hierarchy, and it is not passing on touches to objects below it. Then theres more obscure ones such as : you have implemented an animating image on the button, and it is interfering with touches. Yes - Ive had that issue too.
But Ive never before had this one. Theres another tick box, in the storyboard's UIButton panel, in the 'Control' section. Here you set the alignment of the text content - and just under there, a separate 3 booleans are titled : Selected, Enabled and Highlighted.
And my issue, after two hours of fiddling, turned out to be : that Enabled tick box must be ticked.
I have never come across that issue before. I dont actually know why this is suddenley having an effect on my UIButton. If anyone would care to enlighten me more about this (almost) hidden but essential little tick box, I am all ears!
Meanwhile, make sure this is ticked.
Wednesday, January 20, 2016
Autolayout - nicely stacking UILabels that change size with content
Hi folks, first post in this new blog. This is an overview of how to achieve a nicely stacking set of UILabels using Autolayout, with content for each label that can change on the fly. So the labels need to be able to expand and contract in height, depending on the content, and all other labels need to shuffle up and down with the changes. Heres how it looks in the app :

And heres how it looks in Interface Builder :

So the simple effect is that, when in code, the contents of the labels on the right are changed, the UILabels change size, and the other UILabels move down to accommodate the change. Also though, the key labels on the left move down to stay aligned with the value labels. Simple you'd think - but there are quite a few steps required to achieve this effect, especially when changing text programmatically.
First the UILabels. The text needs to be set correctly to allow the label to expand vertically. There are two settings you need - first, Lines - 0 (which actually means, as many as required); and Line Breaks : Word Wrap.

With autolayout, you need to carefully think about your rules for each object. Each needs info for x & y, width & height. So heres the rules for my objects : the left hand 'key' labels remain a constant width and height (80px x 30px). They are always 0px from the left hand side, and there is always 8px between them and the value labels on the right. Finally, in terms of y origin, they match the y position of the labels on the right (because only the value labels can change height with text changes), and the key labels need to track the vertical position of the value labels.
For the value labels on the right, the rules are : they are always 8px away from the key label on the left, always 8px from the label above, always 8px from the superview edge on the right, and they have flexible height.
Theres two important facts here : that the key labels don't change width or height, and that only the value labels can change height. You need to have a certain amount of fixed sizes like this to make constraints work - if for eg my keys on the left also had a flexible width, it would be too many variable width sizes for autolayout, and it would complain (understandably). So if you can give something a fixed width or height, then do.
First to set the constraints then in IB. So lets do the right hand value label first - top, left, right, and height :

Now the height is going to be flexible for this label. So first we set it to fixed (30px - this will be our base value, so the label will not have a height less than this). To make this flexible, we change it from fixed to 'equal to or greater than'. To do this, double click on this height constraint in the pane on the right, having first selected the object in IB - this allows us to edit the details of the constraint.

Then click on the 'relation' drop down and select 'greater than or equal to' - this is the cunning expandable height option.

Next we do the key label on the left. So it adheres to the left, maintains a set width to the label on the right, and has a constant width and height :

And finally, it needs to keep aligned with the y position of its corresponding value label on the right, as these expand downwards. So we drag from the key label across to the value label, whilst holding down the Ctrl key. This gives us a handy menu where we can select 'Top' - this adds a constraint that keeps the tops of both labels aligned, and gives us the final y value we need for this key label. At this point, autolayout has enough info to lay out both labels, so things should go nice and blue, indicating there are no uncertainties in the rules.

Then the final bit - the code. You can set the contents of these labels in code, and a simple call to setNeedsLayout is all thats required (on the superview) to make it all resize itself correctly. For eg :
And thats it. Please post a comment if anything is not clear or missing for you, thanks.

And heres how it looks in Interface Builder :

So the simple effect is that, when in code, the contents of the labels on the right are changed, the UILabels change size, and the other UILabels move down to accommodate the change. Also though, the key labels on the left move down to stay aligned with the value labels. Simple you'd think - but there are quite a few steps required to achieve this effect, especially when changing text programmatically.
First the UILabels. The text needs to be set correctly to allow the label to expand vertically. There are two settings you need - first, Lines - 0 (which actually means, as many as required); and Line Breaks : Word Wrap.

With autolayout, you need to carefully think about your rules for each object. Each needs info for x & y, width & height. So heres the rules for my objects : the left hand 'key' labels remain a constant width and height (80px x 30px). They are always 0px from the left hand side, and there is always 8px between them and the value labels on the right. Finally, in terms of y origin, they match the y position of the labels on the right (because only the value labels can change height with text changes), and the key labels need to track the vertical position of the value labels.
For the value labels on the right, the rules are : they are always 8px away from the key label on the left, always 8px from the label above, always 8px from the superview edge on the right, and they have flexible height.
Theres two important facts here : that the key labels don't change width or height, and that only the value labels can change height. You need to have a certain amount of fixed sizes like this to make constraints work - if for eg my keys on the left also had a flexible width, it would be too many variable width sizes for autolayout, and it would complain (understandably). So if you can give something a fixed width or height, then do.
First to set the constraints then in IB. So lets do the right hand value label first - top, left, right, and height :

Now the height is going to be flexible for this label. So first we set it to fixed (30px - this will be our base value, so the label will not have a height less than this). To make this flexible, we change it from fixed to 'equal to or greater than'. To do this, double click on this height constraint in the pane on the right, having first selected the object in IB - this allows us to edit the details of the constraint.

Then click on the 'relation' drop down and select 'greater than or equal to' - this is the cunning expandable height option.

Next we do the key label on the left. So it adheres to the left, maintains a set width to the label on the right, and has a constant width and height :

And finally, it needs to keep aligned with the y position of its corresponding value label on the right, as these expand downwards. So we drag from the key label across to the value label, whilst holding down the Ctrl key. This gives us a handy menu where we can select 'Top' - this adds a constraint that keeps the tops of both labels aligned, and gives us the final y value we need for this key label. At this point, autolayout has enough info to lay out both labels, so things should go nice and blue, indicating there are no uncertainties in the rules.

Then the final bit - the code. You can set the contents of these labels in code, and a simple call to setNeedsLayout is all thats required (on the superview) to make it all resize itself correctly. For eg :
And thats it. Please post a comment if anything is not clear or missing for you, thanks.
Subscribe to:
Posts (Atom)
Social Network with Firebase 3 - Infinitely scrolling UITableView of Firebase Items
Ive already talked about the basics of a Firebase social network project , and adding posts in two other articles. Here I want to explain ...
-
Ive already outlined my database structure for my Firebase based social network. Ive done the auth for new users , and Ive added each new ...
-
Im doing an awful lot of work at the moment with AVMutableVideoCompositions, and AVAssetExportSessions. When exporting a video using the la...








