I am fairly new at creating iOS apps and I have a question about a common practice regarding central Text & Color styling in a project.
What I want to do is to define a custom "Header" style, custom "ToolBar" style, custom "Body" style etc. and use them in different UIControlViews in my project.
I want to be able to change one of these styles so that every object using that style adjusts accordingly.
As much as I understand there are no CSS-like styling files when designing an iOS app.
What I was thinking to do is to create a Swift file where my styles are defined as constants in some way and add code blocks in all viewDidLoad methods of UIViewControllers that sets related objects' styles by using these constants.
Is there a better way, or what is the common practice for doing that kind of thing?
Many classes has the protocol UIAppearance which sets their default properties such as font, textColor, backgroundColor etc.
Ex:
UIButton.appearance().backgroundColor = UIColor.redColor()
List of all classes using UIAppearance
As you said create a configuration.swift file that contains your configuration and returns a view based on configuration and then use this configuration to create a custom view. This is the way I did in my last app. Also, check this snippet to get an actual understanding of what I said http://www.objc.io/snippets/20.html
Read about view controller polymorphism and view controller hierarchy.
Base a "parent" view controller on UITableViewController, and include your common properties and methods.
Then base all the "child" view controllers on that "parent".
For example in Objective C:
"Parent" view controller header file...
#import <UIKit/UIKit.h>
#interface MyParentTableViewController : UITableViewController
#end
"Child" view controller header file...
#import <UIKit/UIKit.h>
#interface MyChildTableViewController : MyParentTableViewController
#end
So in this manner all public properties and methods of the parent become available to the child, and only need be written once, in the parent implementation file.
I have been using the pod NUI for styling the complete iphone Application. There are couple of other options like UISS.
There are few other commercial options also, but the above two do a fantastic job of externalizing the styling of the application.
I've used NUI and it enables me to provide multiple themes and even allow the end user to switch themes.
Related
I wonder if there is any frameworks I'm not aware that I can use to achieve the concept of databinding, bind a NSObject derived class (the model) to a UIControl/NSControl derived component properties.
For example I have a class with a property name and I need to bind it to a UITextView text property so that when the model's name property changes the UITextView text property updates.
I guess that there would be something built on the Key-Value Observing concept.
I would like something that is working in both OSX and iOS or any other related frameworks for the platforms.
Thank you.
You're looking for ReactiveCocoa - super awesome framework that does exactly what you asked for and more. Also a good way to implement MVVM - they have cool extensions that enable that ReactiveViewModel as well as extensions for AFNetworking
Take a look at AKA Beacon (https://github.com/mutech/aka-ios-beacon). It's a binding framework that allows you to bind views to properties right from interface builder. The view controller (by default) serves as view model for bindings. You just have to add one line of code to the view controller to activate binding support and the framework takes care for all the rest.
Beacon supports most standard views (Label, TextField/View, Image, Slider, Stepper, Switch, TableView, etc.). It's relatively easy to write extension bindings for custom views.
I'm learning iOS development stuff and what I have found in tutorials and books is that controller layer usually has access to the View's controls directly (textfields, labels etc.). Let's consider such an example:
Assume, that View has a label called lblResult and a textfield called txtDataToAnalyze. Than in controler interface we've got something like this:
#property (nonatomic, retain) IBOutlet UILabel* lblResult;
#property (nonatomic, retain) IBOutlet UITextField* txtDataToAnalyze;
and some #synthesize statements in the implementation file.
I have some experience with JavaSwing development, where most of thinks I'm writing manually without any GUI Builders, and what I usually do in MVC is to access the View's controls via getters/setter. For example: void setResult(String resString); or String getDataToAnalyze();. In that way, controller knows only what pieces of information are displayed in the view, and not how are they displayed. I think it is more flexible (it is easier to change the view layer later).
I know that iOS has some specific rules, has introduced XIB/NIB files etc so maybe my doubts are completely useless in case of iPhone/iPad development. But I am going to write some more serious application for iOS (actually "rewrite" it from Java Swing) and that's why I would like to ask you:
Do you think, I should change the way I am thinking and get accustomed to that new (for me) approach (xib files, creating GUI using drag&drop and providing controler with information about how data should be displayed in view) ?? Did you have similar doubts when starting with iOS?
Short answer:
Yes, I think you should definitely spend a little time getting accustomed to working with Interface Builder (IB) to make NIBs and storyboards and let IB create the IBOutlet and IBAction references for you for those controls with which you need to interact. Once you're proficient at it, you'll be impressed by your productivity in generating easily maintained code. Don't dismiss IB too quickly.
In terms of letting the controller interact directly with the IBOutlet and IBAction references, this is common practice for simple user interfaces. If you have some real world examples, post a new question with a screen snapshot and we can offer more practical guidance.
Long answer:
Part of your question seems to be driven by the apprehension in seeing view controllers that are doing detailed interaction with a view's controls. The thing is, if you want to isolate your controller from some of the implementation details of the view, then go ahead and subclass the view and put the view specific stuff in there. IB can interface with both view controller subclasses as well as view subclasses. So you can happily use IB and still isolate your view controller from some of these implementation details.
Personally, I only do this subclassing of UIView when the view hits some subjective complexity threshold (e.g. for me, that threshold is when I find myself doing some complicated animation, such as using CADisplayLink; complicated gesture recognizers, etc.). I also subclass those subviews that are logical entities of their own (e.g. UITableViewCell or UICollectionViewCell). But for simple views where I'm interacting with my model to setting a control's properties, interacting with text fields, etc., I think putting that in the view controller is fine. Having said that, if I have a lot of view-specific code in my controller which has nothing to do with the integration of my model with my view, then start subclassing the UIView and shifting the view-only code into that.
Implicit in your question is the notion of programmatically building view rather than using NIBs/storyboards. In my opinion, using Interface Builder (IB) to build your UI is much easier to develop and maintain. There might be some pedagogical value to doing a test project where you build your views programmatically, so you really understand what's going on, but after that, I think you'll find yourself quickly gravitating to storyboards. And you'll get plenty of chances to write your own non-IB code when you start doing things beyond the capabilities of the standard IB controls (e.g. complicated custom container views, etc.). There are definitely those who prefer to develop views programmatically, but I don't think you can beat the development speed and ease of maintenance of IB generated UIs.
I general, the controller does not know about the view, but the view knows about the controller.
The gang of four book says:
"MVC also lets you change the way a view responds to user input without changing its visual presentation. You might want to change the way it responds to the keyboard, for example, or have it use a pop-up menu instead of command keys. MVC encapsulates the response mechanism in a Controller object. There is a class hierarchy of controllers, making it easy to create a new controller as a variation on an existing one.
A view uses an instance of a Controller subclass to implement a particular response strategy; to implement a different strategy, simply replace the instance with a different kind of controller. It's even possible to change a view's controller at run-time to let the view change the way it responds to user input. For example, a view can be disabled so that it doesn't accept input simply by giving it a controller that ignores input events.
The View-Controller relationship is an example of the Strategy (315) design pattern. A Strategy is an object that represents an algorithm. It's useful when you want to replace the algorithm either statically or dynamically, when you have a lot of variants of the algorithm, or when the algorithm has complex data structures that you want to encapsulate."
A quick question from a wanna-be iOS developer. I want to create a UI for an iPhone app without Interface Builder, only programmatically. However, I want to stick to MVC recommendations and separate V and C and have a clean readable code, therefore:
I create UIView class files (e.x. SplashView.h and SplashView.m)
I create UIViewController class files (SplashViewController.h and SplashViewController.m)
I define my UI elements (view, subviews, buttons and text fields) in the UIView class files
I load the main view in view controller's loadView method, and then do other things in view controller's viewDidLoad method
Is this a correct approach to begin with?
Second part of the question, independent of Y/N answer to the first. Where do I define these custom UI elements?
- Inside the view's initWithFrame: method?
- In separate (property getter? property setter?) methods? I.e. do I have to declare each UI element as a property first in the .h file?
If these questions sound a bit ignorant, it must be because they are :) I found lots of sample code on StackOverflow, but little to indicate where you actually put it. I would be really grateful for any help, especially if you could paste/reference some relevant code.
Your list is correct. This is how I do all of my apps. No Interface Builder, just code.
Each custom view typically creates its own subviews in an appropriate initXXX method. This could be initWithFrame: but you could define others as needed. Subview layout can be done through constraints, autoresizing masks, or by implementing layoutSubview.
Each view controller would instantiate its needed views in the viewDidLoad. View layout can be done with constraints, autoresizing masks, or by implementing viewWillLayoutSubviews.
The use of properties is completely optional. Create public properties for anything to be set/get from an outside class. Optionally create private properties for values internal to the implementation.
Go to the Apple website for Sample Code; download everything that you can for applications that are similar to your goal.
I have a .m file, containing a #implementation ,
but it has gotten too big and I'm trying to move some of the method functions to a 2nd file.
Both .m files begin with
#implementation GesticulatorViewController
#synthesize score_display;
#synthesize game_status;
#synthesize player_options;
#synthesize total_players_field;
#synthesize gesticulation_sentence;
#synthesize gesticulation_input;
#synthesize main_view_manager;
#synthesize game_state;
But I'm getting linker warning:
"ld: duplicate symbol _OBJC_IVAR_$_GesticulatorViewController.gesticulation_input "
You cannot have the same class implementation in two different files.
In your case, you cannot split the implementation of GesticulatorViewController into two .m files.
EDIT:
I would use Objective-C categories to disperse the implementation.
With categories, you have the opportunity to group together methods that perform similar tasks.
Here's an explanation of "Categories and Extensions" from Apple's documentation:
https://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1
I would recommend making more than one controller. Each controller handles a different piece.
I am making a video app. I have a PlayerControlsViewController, it has all the Play and pause buttons within its view.
I have also a Tools controller which has the selection tools and any menu items within it.
The properties for those controllers take that controllers view and remove from super view. then set the view somewhere within its own view and connects it to the PlayerController. which houses the player within it.
Each of these controllers houses its own code to handle its tasks. And sends messages back to the main view controller via a protocol for each.
This will relay commands back and forth between the other controllers, and maintain the setting on the main view controller.
This I believe is the expected standard of operation for the apps to function correctly, and be easily maintainable.
This method also works with Navigation controllers and Tab controllers.
Since they maintain their own code, you can add another view controllers view within your own view.
Just remember to remove it from its superview before adding it to your view.
If it all needs to be in one view, but you think the implementation is too large, you can always do categories :) Just go to File->New->Objective-C Category. Then make the category on your view controller, and add it!
Just remember you cannot add new ivars or properties in the category. You can, however, utilize properties and ivars from your original class.
Also, if you find that you have a LOT of code in your .m view controller files, you might think about looking a little further into the MVC paradigm to split some functionality into other classes. Remember, the view controller should only handle view changes - data manipulation, etc. should be done by other classes :)
Another option would be to copy the source code for some of the methods to another .m file, then #include that file in the main .m file. Put the #include at the point where you cut methods out of the main file.
The trick to making this work is to add the #included source file to your project, but un-check all targets. You don't want Xcode to try to compile the file on it's own - only #include it in your main view controller file.
I'd like to add some custom buttons to an ABUnknownPersonView. Can I use initWithNibName:bundle: in my ABUnknownPersonViewController to load a custom view that I've created in IB, while not using an "undocumented api?" And if I do, how can I make sure that it follows all the properties and responds to all the hooks that the controller expects?
I typically create all my views programmatically and I generally like the view that ABUnknownPersonViewController creates. I'd rather just start from there. And so I accessed the view and dropped in a button, but with later versions of iOS that broke since that isn't a hook that Apple created.
initWithNibName is also not mentioned in the ABUnknownPersonViewController documentation but it is a method of it's parent class UIViewController. Does that make it safe to use?
You cannot provide a replacement XIB. While I understand you want to avoid it, you will have to use the underlying AddressBook framework and building your own version out of it.
You can, of course, look at open source stuff such as this for a good starting point.