I've inherited a long term maintenance code base that has two radically different iPhone and iPad views. This has created one large UIViewController class that has ballooned to over 1k lines of code, is a mashup of ISIPAD statements, private vars, properties, iBOutlets/Actions and, for example, uses a UITableView for one implementation and something completely different for another.
To make matters worse the current software pattern relies on subclassing.
Currently we look like this:
ParentVC (both iphone/ipad God class also has xib(xib~ipad) + iboutlets/actions)
| | |
ChildA ChildB ChildC
My initial thought was to take the ParentVC and split it into iPhone/iPad specific classes
ParentVCBase
| |
ParentVC_iPad(xib~ipad) ParentVC_iPhone(xib)
| |
ChildA/B/C_iPad ChildA/B/C_iPhone
and spit out the correct Child subclass via a factory call.
The issue I've encountered is that each Child overrides a few ParentVC method calls and implements it's own feature specific methods that are not device specific (keep in mind the main goal of the original subclassing was to share view layout). This design pattern would only work if I were to duplicate code for ChildA_iPhone and ChildB_iPad. I'd rather avoid that as I've traded one anti-pattern for another.
I'm a at a bit of a loss here. I've almost considered creating the Child classes at runtime (objc/runtime.h), swizzeling the required Child methods from a reference Child class but that doesn't seem any less of a mess than we currently have. To simply clean up I've also considered keeping the ParentVC header (with it's large list of IBOUTlets, properties, etc) and putting device specific methods into categories to at least separate the functionality until the day a real refactor is needed.
Curious if there are any iOS architects that have had to deal with this at one point in time or how they might deal with it.
This isn't an iOS specific question as much as it is a object-oriented design question.
You definitely want to avoid code duplication. Duplication is the source of much evil.
In general, what you want do is avoid being restricted by the limitations of inheritance in designing your classes. What you want to move towards is class composition.
So you could move to a design that looks like this using the bridge pattern:
ParentVC ---> ImplementationA
| | | |
ChildA ChildB Implementation_iPhone Implementation_iPad
Here, ParentVC has the same class hierarchy as above, but it uses a separate class hierarchy, ImplementationA, for implementation. That class hierarchy breaks down into iPhone and iPad versions. Class ImplementationA holds the guts of the implementation that was in ParentVC.
Inheritance is a design pattern, but it is just one of many. If you stick to just using that one pattern you'll get stuck into making bad designs. You need to combine patterns to properly model the system.
Of course, be sure to use unit tests, as much as possible, to ensure you don't break anything when you're making these changes.
Related
First of all i know MVC well and have been using it in project but when it comes to organizing classes and there role i am bit not sure of there proper implementation. Lets take a scenario to proceed with:
A sample which will display All Employee and Department. Data will be fetched from Web Services(Json) and will be stored as offline(Core Data).
So MVC pattern would be:
View will be my storyboard with Employee and Department UIViewController.
Controller will be EmployeeViewController.swift and DepartmentViewController.swift
Model will be Employee.swift and Department.swift
class Employee: NSObject {
var name: String?
}
class Department: NSObject {
var departmentName: String?
}
ServiceManager which will make calls to the web service.
ParseData which will parse the web service response and convert it into Employee and Department objects
CoreDataManager is singleton class to manage CRUD operation on offline DB.
Here are series of question on the above scenario which i have:
Is my understanding correct? Is the structure which i am trying to build follows proper MVC?
How the controller will interact with these components (Service Manager, ParseData, CoreDataManager). Should there be another class which will facilitate the communication between controller and data management(if controller does this then it will a tightly-coupled structure and massive as well).
Should Model be having any code other then property and initialization method as most of the model which i have seen only have property declaration?
Should there be separate UIView classes instead of storyboard to create a proper MVC structure?
Is my understanding correct? Is the structure which i am trying to
build follows proper MVC?
First I will say that "proper" MVC will depend on who you're asking. Its origin is commonly attributed to Trygve Reenskaug when he introduced this into Smalltalk in the 70's. However, his type of MVC was widely different from the bloated versions most commonly used today. The modern way of thinking about MVC is
Model = mostly a dumb class which primarily encapsulates data
View = whatever we present on the screen
Controller = the big lump of code that does almost everything,
sometimes offloaded by a manager class or two of some sort
Reenskaug, however, would have a model and a view and a controller for a button. For a label. For a field. I'm not saying that is what we should strive for, but there should be better ways to structure a project than using the Massive ViewController pattern (as it is jokingly referred to in the iOS community).
Luckily, there are.
Uncle Bob is preaching Clean Architecture. There are several implementations of this, and various people have made their own implementations of this for iOS, like VIPER and Clean Swift.
How the controller will interact with these components (Service
Manager, ParseData, CoreDataManager). Should there be another class
which will facilitate the communication between controller and data
management(if controller does this then it will a tightly-coupled
structure and massive as well).
Following the principles of Clean Architecture, you should encapsulate these functionalities into layers, in a way that enables you not just to split the code into multiple components, but also enables you to replace them with other components when that is needed. (But yes, at the very least avoid putting all of this in your controller!)
Should Model be having any code other then property and initialization
method as most of the model which i have seen only have property
declaration?
Again, there is not a single answer here. Some proponents of "real" OOP will say that each object should be self-served (i.e. a model object should know how to persist itself), while others extract the knowledge of such operations into "managers". Putting code to persist an object into the object could mean littering persistence functionality into many objects, or require you to rely on subclassing or other solutions to avoid this coupling.
Should there be separate UIView classes instead of storyboard to
create a proper MVC structure?
Storyboard or not does not determine whether you're using "proper" MVC. Also, what kind of class you're choosing (UIView or UIViewController) to represent the View is also not important. Your ViewController can be dumbed down to such a degree that it contains no logic (forwarding the logic that it DOES have to another class, i.e. the Presenter in VIPER).
I would recommend reading about the Clean Architecture and maybe watch a video of Uncle Bob explaining it, read other people's reports on implementing it, and then consider whether MVC is the correct pattern for your iOS project.
I have a few ViewControllers in my storyboard. Lets call them:
SB_VC1
SB_VC2
SB_VC3
I have one ViewController.swift file. Within that file, I have multiple ViewController classes, let's call them:
VC_Class_1
VC_Class_2
VC_Class_3
Each VC_Class is used as its corresponding SB_VC's class. Each VC_Class has different code, tailored to what I want the SB_VC to do.
These are all on the same hierarchy level, none is a subview of another. They each inherit from UIViewController and import UIKit and CoreData.
Question:
Part 1
Is keeping the code for all three classes in one file wrong? Should I be creating a new file for each VC_Class? Or is this just a matter of personal preference? If it is not preference and is clearly wrong, what is the problem it causes?
Part 2
If all three do have a little bit of overlap, in terms of each having a few functions that are the same, should I create a fourth class and call it something like "ToolBox.swift" and use it to call those functions? Or would it be better to have VC_Class_1 house those functions and make VC_Class_2 and VC_Class_3 inherit from VC_Class_1?
Generally, it is a matter of preference. Though I'd highly advise against it. Large files are harder to maintain, and it will take you longer and longer to find pieces of code you need. It will also be easier for other people to read and undestand your code.
As for the common code, it depends on its nature. You can either create a Toolbox class or a superclass from which you will inherit.
I am trying to implement component for possibility to apply different skins to views and controllers at runtime without reinitialising these controls. I want to use such logic:
Declare protocol with methods for applying skins.
All necessary classes implements this protocol.
When user selects skin all instances of classes that conform to protocol receive message to apply skin.
So I know how to get all necessary classes that conform to my specific protocol by using objc_getClassList and class_conformsToProtocol functions.
But how to get all allocated instances of these classes for sending message to them?
I know that it could be implemented by internal logic of every class by storing all instances in static storage and returning array by class method. But it isn't elegant solution. I'm finding more universal solution where I can add new skinnable controls in easy way.
It sounds very much like you're reinventing <UIAppearance>. You should at least start there. It's what it's for. Also see Peter Steinberger's writeup for discussion of adding custom properties.
To your basic question, there is not a runtime call to enumerate all allocated objects of a class. It would add a lot of overhead to provide that (objects come and go all the time and very quickly). Even if you could do it, you probably shouldn't. But since you're talking about visible views, then you can always do this by enumerating the view hierarchy under NSWindow. Any views not currently in the view hierarchy should be expected to correctly redraw in an new style the next time they come on the screen.
But I'd start with <UIAppearance>.
I have a situation where I have a purely static stateless facade for providing access to a collection of services. I'm considering using NS_ROOT_CLASS as an alternative to providing a base class, since the facade has no memory management needs. Consider:
NS_ROOT_CLASS
#interface UtilityThing
+ (void) Service1;
+ (void) Service2;
#end
Service1 & Service2 effectively represent 'singleton-like' instances of service classes. So calling code looks like:
[[UtilityThing Service1] thingService1Does];
Aside from the fact that it has no instance data, I chose NS_ROOT_CLASS in part to simplify usage of the class, so that the only code-completion suggestions are the relevant ones (re: XCode 5: Is there any way to group/filter/sort what shows up in code-completion?)
Does anyone know if there are any gotchas to this pattern which might prevent an application from passing certification? Or if there are other technical considerations that I should make when using NS_ROOT_CLASS?
Yes, you can do that.
But don't.
Defining a new root class -- even a new root class containing nothing but class methods -- is an exceedingly atypical pattern. I.e. pretty much never done. Never done to the point that it is likely that the debugger and/or other dev tools may treat it slightly oddly.
Just declare it to be a subclass of NSObject. Or create a singleton and make them instance methods because, almost assuredly, you'll end up wanting to store state as a part of your utilities and you'll have to refactor at that point.
Note: Methods should start with lower case letters.
Everything is OK. You are allowed to create your own root class. It looks correct if you do not need to create instances of UtilityThing.
I'm currently working on a Rails project, and have found times where it's easiest to do
if object.class == Foo
...
else if object.class == Bar
...
else
...
I started doing this in views where I needed to display different objects in different ways, but have found myself using it in other places now, such as in functions that take objects as arguments. I'm not precisely sure why, but I feel like this is not good practice.
If it's not good practice, why so?
If it's totally fine, when are times that one might want to use this specifically?
Thanks!
Not sure why that works for you at all. When you need to test whether object is instance of class Foo you should use
object.is_a? Foo
But it's not a good practice in Ruby anyway. It'd much better to use polymorphism whenever it's possible. For example, if somewhere in the code you can have object of two different classes and you need to display them differently you can define display method in both classes. After that you can call object.display and object will be displayed using method defined in the corresponding class.
Advantage of that approach is that when you need to add support for the third class or a whole bunch of new classes all you'll need to do is define display method in every one of them. But nothing will change in places where you actually using this method.
It's better to express type specific behavior using subtyping.
Let the objects know how they are displays. Create a method Display() and pass all you need from outside as parameter. Let "Foo" know to display foo and "Bar" know how to display bar.
There are many articles on replacing conditionals with polymorphism.
It’s not a good idea for several reasons. One of them is duck typing – once you start explicitly checking for object class in the code, you can no longer simply pass an instance of a different class that conforms to a similar interface as the original object. This makes proxying, mocking and other common design tricks harder. (The point can be also generalized as breaking encapsulation. It can be argued that the object’s class is an implementation detail that you as a consumer should not be interested in. Broken encapsulation ≈ tight coupling ≈ pain.)
Another reason is extensibility. When you have a giant switch over the object type and want to add one more case, you have to alter the switch code. If this code is embedded in a library, for example, the library users can’t simply extend the library’s behaviour without altering the library code. Ideally all behaviour of an object should be a part of the object itself, so that you can add new behaviour just by adding more object types.
If you need to display different objects in a different way, can’t you simply make the drawing code a part of the object?