What are the pros and cons of Storyboards and Segues in Xcode 5/iOS 7? - uiviewcontroller

I'm starting a new project from scratch, and while I've also been creating and handling views and viewcontrollers programmatically so far (some some xibs from time to time, for some simple views), I'm now wondering if it's time to switch to Storyboards. It looks like Apple is pushing for them really hard, and maybe I shouldn't fight against them and embrace the new approach? (not really new, but maybe now mature?)

Pros:
You can really see your app and the connections between the app. If you have some UI that doesn't need logic (for example Terms Of Service with some static text and an Agree button that takes you to the next screen) you don't even need to create the controller part of that.
Cons:
If you're in a big team, storyboards can be really hard to merge when using version control.
Fore more info:
http://www.youtube.com/watch?v=XciUazpOfFU

Almost only cons. Here's is a list of their problems, copied from iraycd:
Storyboards fail at runtime, not at compile time: You have a typo in a segue name or connected it wrong in your storyboard? It will blow up at runtime. You use a custom UIViewController subclass that doesn't exist anymore in your storyboard? It will blow up at runtime. If you do such things in code, you will catch them early on, during compile time. Update: My new tool StoryboardLint mostly solves this problem.
Storyboards get confusing fast: As your project grows, your storyboard gets increasingly more difficult to navigate. Also, if multiple view controllers have multiple segues to multiple other view controllers, your storyboard quickly starts to look like a bowl of spaghetti and you'll find yourself zooming in and out and scrolling all over the place to find the view controller you are looking for and to find out what segue points where. Update: This problem can mostly be solved by splitting your Storyboard up into multiple Storyboards, as described in this article by Pilky and this article by Robert Brown.
Storyboards make working in a team harder: Because you usually only have one huge storyboard file for your project, having multiple developers regularly making changes to that one file can be a headache: Changes need to be merged and conflicts resolved. When a conflict occurs, it is hard to tell how to resolve it: Xcode generates the storyboard XML file and it was not really designed with the goal in mind that a human would have to read, let alone edit it.
Storyboards make code reviews hard or nearly impossible: Peer code reviews are a great thing to do on your team. However, when you make changes to a storyboard, it is almost impossible to review these changes with a different developer. All you can pull up is a diff of a huge XML file. Deciphering what really changed and if those changes are correct or if they broke something is really hard.
Storyboards hinder code reuse: In my iOS projects, I usually create a class that contains all the colors and fonts and margins and insets that I use throughout the app to give it a consistent look and feel: It's a one line change if I have to adjust any of those values for the whole app. If you set such values in the storyboard, you duplicate them and will need to find every single occurrence when you want to change them. Chances are high that you miss one, because there's no search and replace in storyboards.
Storyboards make you do everything twice: Are you building a universal app that runs both on iPad and on iPhone? When you use storyboards, you will usually have one storyboard for the iPad version and one for the iPhone version. Keeping both in sync requires you to do every UI or app-workflow change in two places. Yay. Update: In iOS 8 and Xcode 6, you can use a single Storyboard for iPhone and iPad.
Storyboards require constant context switches: I find myself working and navigating much faster in code than in storyboards. When your app uses storyboards, you constantly switch your context: "Oh, I want a tap on this table view cell to load a different view controller. I now have to open up the storyboard, find the right view controller, create a new segue to the other view controller (that I also have to find), give the segue a name, remember that name (I can't use constants or variables in storyboards), switch back to code and hope I don't mistype the name of that segue for my prepareForSegue method. How I wish I could just type those 3 lines of code right here where I am!" No, it's not fun. Switching between code and storyboard (and between keyboard and mouse) gets old fast and slows you down.
Storyboards are hard to refactor: When you refactor your code, you have to make sure it still matches what your storyboard expects. When you move things around in your storyboard, you will only find out at runtime if it still works with your code. It feels to me as if I have to keep two worlds in sync. It feels brittle and discourages change in my humble opinion.
Storyboards are not searchable: A project-wide search in Xcode is not really a project-wide search when you use storyboards. They are not included in the search. So when you remove a custom class from your code or rename it, you will have to manually go through the storyboard or look at its raw XML to make sure it is on par with your code changes. No sir, I don't like it. Update: Storyboards are searchable in Xcode 6.
Storyboards are less flexible: In code, you can basically do anything you want! With storyboards you are limited to a subset of what you can do in code. Especially when you want to do some advanced things with animations and transitions you will find yourself "fighting the storyboard" to get it to work.
Storyboards don't let you change the type of special view controllers: You want to change a UITableViewController into a UICollectionViewController? Or into a plain UIViewController? Not possible in a Storyboard. You have to delete the old view controller and create a new one and re-connect all the segues. It's much easier to do such a change in code.
Storyboards add two extra liabilities to your project: (1) The Storyboard Editor tool that generates the storyboard XML and (2) the runtime component that parses the XML and creates UI and controller objects from it. Both parts can have bugs that you can't fix.
Storyboards don't allow you to add a subview to a UIImageView: Who knows why.
Storyboards don't allow you to enable Auto Layout for individual View(-Controller)s: By checking/unchecking the Auto Layout option in a Storyboard, the change is applied to ALL controllers in the Storyboard. (Thanks to Sava Mazăre for this point!)
Storyboards have a higher risk of breaking backwards compatibility: Xcode sometimes changes the Storyboard file format and doesn't guarantee in any way that you will be able to open Storyboard files that you create today a few years or even months from now. (Thanks to thoughtadvances for this point. See the original comment)
It's McDonald's: To say it in Steve Jobs' words about Microsoft: It's McDonald's (video)!

One other Pro exclusive to UIStoryboards: Static table view cells. Per Apple, "With static content, the number of rows is a finite quantity that’s known at compile time. A table view that presents a detail view of an item is a good candidate for static content."

Related

Static or Dynamic options in dropdown menu, which is better for Automation Testing?

Here is my problem with my dropdowns:
As an automation tester, I have some issues using Selenium's Select(); method 'bout dropdown fields. If I have to run a test in multiple cycles and select different option from the dropdown every next cycle, I just used Select(); method and it worked great.
Now the problem is that in the HTML code I do not even see the option of the dropdown. The field is changed to dynamic, it is not static anymore.
How can I work around this feature or is it just a bad programming practice?
I think it's not bad practice to have dynamic options in a dropdown menu.
To write an end-to-end test for this it depends how dynamic these options are. If they change from release to release (e.g. the available product categories in the system), you should probably encode them in your test. In that way the test will have to be updated if the options are updated, which makes sense (the test will fail if it doesn't find the options it expects).
If the options change by external factors (e.g. the current top 10 trending topics on Twitter) then you cannot encode them in your test. You should then probably try to pick one by index (e.g. the first one) and parameterize the test to handle any value that might be there. Alternatively you could stub the 'TrendingValuesFromTwitterService' (staying with my example) to deliver a fixed set of values for your testing purposes.
Normally static data with Select, Dropdown or combobox is a best practice. Unfortunately, sometimes we need dynamic data with Selects. The best way is to use Fluent Waits for Select contains your option. Also, Thread.sleep() is another solution but it is not preferable. However, it is exact solution. Try to implement fluent or implicit waits for your select options.
For example, ElementToBeVisible or ElementToBeExists etc.
Checkout Selenium Docs

Restructuring to avoid accessing components in models

Continuing to work on my port of a CakePHP 1.3 app to 3.0, and have run into another issue. I have a number of areas where functionality varies based on certain settings, and I have previously used a modular component approach. For example, Leagues can have round-robin, ladder or tournament scheduling. This impacts on the scheduling algorithm itself, such that there are different settings required to configure each type, but also dictates the way standings are rendered, ties are broken, etc. (This is just one of 10 areas where I have something similar, though not all of these suffer from the problem below.)
My solution to this in the past was to create a LeagueComponent with a base implementation, and then extend that class as LeagueRoundRobinComponent, LeagueLadderComponent and LeagueTournamentComponent. When controllers need to do anything algorithm-specific, they check the schedule_type field in the leagues table, create the appropriate component, and call functions in it. This still works just fine.
I mentioned that this also affects views. The old solution for this was to pass the league component object from the controller to the view via $this->set. The view can then query it for various functionality. This is admittedly a bit kludgy, but the obvious alternative seems to be extracting all the info the view might require and setting it all individually, which doesn't seem to me to be a lot better. If there's a better option, I'm open to it, but I'm not overly concerned about this at the moment.
The problem I've encountered is when tables need to get some of that component info. The issue at hand is when I am saving my add/edit form and need to deal with the custom settings. In order to be as flexible as possible for the future, I don't have all of these possible setting fields represented in the database, but rather serialize them into a single "custom" column. (Reading this all works quite nicely with a custom constructor and getters.) I had previously done this by loading the component from the beforeSave function in the League model, calling the function that returns the list of schedule-specific settings, extracting those values and serializing them. But with the changes to component access in 3.0, it seems I can no longer create the component in my new beforeMarshal function.
I suppose the controller could "pass" the component to the table by setting it as a property, but that feels like a major kludge, and there must be a better way. It doesn't seem like extending the table class is a good solution, because that would horribly complicate associations. I don't think that custom types are the solution, as I don't see how they'd access a component either. I'm leaning towards passing just the list of fields from the controller to the model, that's more of a "configuration" method. Speaking of configuration, I suppose it could all just go into the central Configure data store, but that's always felt to me like somewhere that you only put "small" data. I'm wondering if there's a better design pattern I could follow that would let the table continue to take care of these implementation details on its own without the controller needing to get involved; if at some point I decide to change from the serialized method to adding all of the possible columns, it would be nice to have those changes restricted to the table class.
Oh, and keep in mind that this list of custom settings is needed in both a view and the table, so whatever solution is proposed will ideally provide a way for both of them to access it, rather than requiring duplication of code.

What are the advantages of using cocos2d-x 3.0 over cocos2d-x 2.x?

Cocos2d-x 3.0 alpha was released for some time now. What was improved over cocos2dx-2?
The features list is quite important, but in terms of performance are there new limitations/improvements?
Have you noticed real improvements in performance, development patterns, APIs and support?
I've been using it recently and from what I've noticed the main differences are that everything is namespaced now, so you don't have to deal with the prefixed names that came from the objective c patterns, so cocos2d::Point instead of CCPoint (especially for enums, (Texture2D::PixelFormat::RGBA8888 instead of kCCTexture2DPixelFormat_RGBA8888)).
Also some of the event stuff now has support for c++11 lambdas.
A more complete list of the changes can be found here: http://www.cocos2d-x.org/wiki/Release_Notes_for_Cocos2d-x_v300
but for the most part of using it myself, it's just made to feel more like C++, instead of like objective-c.
I have switched and am finding it pretty stable. The main advantages so far ...
Real buttons, instead of menus
Real-time spritesheets
SpriteBatchNodes are no longer recommended and I did see a drop in draw calls where I not optimized
less objective C patterns.
more modern. namespaced instead of 'CC'. C++11.
more platforms supported
Main disadvantages for me:
EventListener pattern. I can't figure out how to get touch input to affect any objects other than the Node that triggered the event.
We use a lot of text-only buttons for debugging and they are hard to lay out :)
Lack of documentation and example code. For example, I could not find any documentation of how to use the Layout class anywhere.
It is a lot of work porting, but for us we had to decided to risk it since we would end up maintaining an out-of-date code base. It took about 5 person-days to port our game over. The game is now stable and we did not run into a single bug in cocos.
I think its C++11
auto
lambda
And it has no unnecessary use of prefix CC
One of the changes that happened between Cocos2d-x 2.1.5 and 2.2 was the removal of templates for projects in XCode (I do not know if project templates existed in VS, etc).
The new build system creates projects under the Cocos2d-x installation (at least on Mac) and that is where the project files appear to reference them. This makes it very difficult to move the project without hand tweaking. It also makes configuration management more painful, depending on how you set up your system (e.g. a root/tree like svn or a "drop it anywhere" like git).
Also, the Cocos2d-x library is built as that, a library. In previous incarnations, it was placed directly into the project. On one hand, if you don't alter the root library code, this makes good sense. On the other hand, if you occasionally tweak things for a specific project, you have altered all your projects that depend on it. Yin/Yang.
I'm still very positive on Cocos2d-x. I have not upgraded to 3.0 or 2.2 yet. When it matures a little more, I will switch over, regardless the changes. For what I need, I'm pretty sure it will still get the job done (well).

How should source code files be organized? By function, or type?

In my early coding days, I would tend to group classes that functioned in a similar way. For example:
Data transfer objects
Object A
Object B
Dialogs
Dialog A
Dialog B
After a while, it started to frustrate me that when I was working on a particular part of the application, I would have to jump all around to piece it together.
In the last few years, I tend to organize things by feature. Classes that are commonly shared, such as database objects, I still keep together. I think this even makes sense for things like websites:
Page A
images
Resource 1
Dialog 1
Page B
images
Resource 2
Dialog 2
Is this the best way to do it? Does anyone have a good rule of thumb to follow?
For Java, packages are the unit of reuse.
For Python, modules (as well as packages) are the unit(s) of reuse.
The package should be a stand-alone thing.
If you put all data transfer objects into one big package, you don't have something terribly reusable. You might not want all those data transfer object definitions.
If you put things together by "entity" -- the model, the views, the controls, the data access, etc. -- then you have a reusable module that can be shared in other applications.
The 'Package-by-Feature' approach seems sensible and works for me, certainly for Java... how often do you want to pack up your data access layer, vs. that nifty new feature?
I thought the analysis "Package by feature, not layer" at javapractises.com was pretty easy to read, and covered a couple of angles I'd not thought about, like how package by feature works in other domains than programming, too.
You should do it the way other code using your language/tools do it. This is not a language-agnostic question; some languages/tools expect a relationship between 'file organization' and 'what's in those files' and you should respect that.

With Rails, where should I put html snippets? I don't want partials but I want them reloaded during development

Being lazy (and liking DRY code), I'm the kind of guy who's going to write a few little wrappers for recurring HTML markup. Those provided by Rails are good already, but sometimes I have something a little more specific that I know I'm going to repeat over and over.
In some situations a partial can be the solution, but sometimes I'm just going to call the snippet way too often to justify the overhead of using partials.
Right now I create a helpers/html_helper.rb file and stick them in there. The problem is that helpers are not reloaded dynamically per request during development. So each time I tweak my snippet or the code around it, I have to kill the server and restart it.
Granted, it's just a 5 seconds process, but I love Rails' convenience of just developing and then refreshing the browser. So I'd love to have that for my markup snippets as well.
Note: Just sticking 'unloadable' inside the helper module doesn't work.
Good question! This is a technique I should abuse more frequently.
#I go in environment.db (presumably it will work in one of the per-environment files, too.)
Dependencies.explicitly_unloadable_constants << 'NameOfHelperToReloadHere'
That array starts out empty, incidentally, at least in my install. (Checked via console.)
I tested this locally and it works for me, at least on Rails 2.0.2. Major credit for the solution belongs to this gentleman.
If you stick them in application_helper.rb they'll be loaded every time and be available for all of your views. This is loaded every time in development mode (or at least I haven't encountered any issues).
I typically will create little helpers that I use throughout the site (sortable table headers for instance) that use the same logic.
This should reload ALL helpers on every request (assuming you've stuck to the default naming conventions)
#Put this in config/environments/development.rb
ActiveSupport::Dependencies.explicitly_unloadable_constants.concat(Dir.glob("#{RAILS_ROOT}/app/helpers/**/*.rb").map {|file| File.basename(file, '.rb').camelize})
Or if you are using an older version of Rails (2.0.2 or earlier I think)
#Put this in config/environments/development.rb
Dependencies.explicitly_unloadable_constants.concat(Dir.glob("#{RAILS_ROOT}/app/helpers/**/*.rb").map {|file| File.basename(file, '.rb').camelize})
Works for me in RoR 2.1.1
Update: modified top snippet to include 'ActiveSupport::', must have copied / pasted incorrectly from my code.
It's not a real solution but you could use tests (TestUnit, RSpec or whatever) to make sure your helpers work as expected. That way, you wouldn't rely on automatic reloading of your helpers so much.