I have two Swift classes in two different files, both in the same target. Is there a way to give one access to the private members of the other without exposing them as internal or public?
(I'm essentially looking for something analogous to friend in C++.)
Motivation:
This could be useful for something like implementing UIViewControllerAnimatedTransitioning in a separate "transition" class—typically requiring intimate knowledge of the source and destination view controllers—without requiring those view controllers to expose private subviews to the rest of the target.
I have two Swift classes in two different files, both in the same target. Is there a way to give one access to the private members of the other without exposing them as internal or public?
No. The rules you get are the rules you get. There is not some magic way to break them. You can put the two types in the same file, or (at the other extreme) you can move them both off into a module of their own and give them internal scope so that they can see each other but no one else can see them.
This could be useful for something like implementing UIViewControllerAnimatedTransitioning in a separate "transition" class—typically requiring intimate knowledge of the source and destination view controllers—without requiring those view controllers to expose private subviews to the rest of the target
I don't see why you need this. It is easy to move UIViewControllerAnimatedTransitioning material into a file of its own already. There is no need for exposure of private subviews. That is why this stuff has been broken off into a separate protocol. The roles of animator and view controller are already completely independent. If you think exposure of private subviews is required, you're doing something wrong (and you should be asking a question about that). [For example, it may be that you are unaware of the transitionCoordinator function, which allows a view controller to participate in its transition animation without knowing what it is.]
Related
I am bit new to app development in SwiftUI. In last 2-3 months I have developed few small iOS app just to learn concepts. Otherwise I am experienced developer in C#, Java etc.
One thing I am little unsure about SwiftUI is the right set of architecture around developing classes for the project. I mean like there could be couple of ways
We write model classes that represent the data that our application need to hold. In purist form the model classes should only be concerned about just data, I mean the model classes should only hold the attributes that reflect the data.
Say I am writing a Inventory management app so if one of the model is Merchandise item then its attribute could be Id, name, price, barcode etc. In my opinion the model classes should not concerned about View's concern like #Published, #ObservableObject, #State, #EnvironmentObject etc etc. Model should just stick to representing domain only. Correct?
Ideally the model classes should be written as Class not Struct (if I carry over my understanding of OOPS from C++ to Java/C# where we write classes not struct)
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Now in between the model classes (presuming they are classes or at max we made them Struct for the sake of SwiftUI framework) and View classes, lots of communication, state change, eventing has to happen to make app worthy of doing something. I mean handling user gestures, creating & editing data which should update screens when user navigate back and forth between UIs.
I found it little hard to connect Model (if they are developed in purist form) and View. Hard in the sense that as I started writing Views and look to implement use cases which involve data editing, reflecting changes in views etc I found pure model classes insufficient. They have to be modified to reflect SwiftUI features like binding, observability, published to sync data between view and model and also between two models.
Wondering what is the right design pattern to connect and communicate between model and view? Is MVVM the right design pattern to be used in SwiftUI based project? If not then what else is right pattern?
If MVVM is right pattern then are there any quality guide or resources or sample SwiftUI projects (gitHub??) I can look at and learn?
I think your hypothesis is wrong.
Ideally the model classes should be written as Class not Struct
Make a distinction between model with and without state.
Model without state should be value type.
Model with state should be reference type.
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Value type cannot be inherited. I also think they are models rather than views.
E.g.; struct Model: View {}
They are models, that can be used to build views, hence the View conformance.
The fact that it is of value type also supports that it's not view. (cannot be inherited)
Whether your model has state or not, as long as it conforms to View, it can be used to render a view. This is the design of SwiftUI, taking a page from React, IMO. (I personally don't see React ever bothering with MVVM)
Now since you think Model should be strictly without state, you have a problem.
You need a reference type object that handles all the state and bridge it to the view.
You can follow MVVM. In that case you lose most of the SDK support that builds around struct Model: View, e.g.; #State, #StateObject, #EnvironmentObject, and associated automatic binding and safety checks. You would also add at least one reference type for each of the views, and put most of the control / business logic in it. (where else can you put it?)
So it's in effect a view controller. And you would be doing most of the Control work on a reference type object, without safe guards of immutability. That is on top of all the overheads you would introduce; and since you would pass view model around to be "reusable", you are going to have all the usual bugs caused by shared reference with implicit states.
Take my above assessment with a grain of salt, of course.
Or you can do what official guide do: struct Model: View {} with possible states in it.
The key here, as SDK requires you to put extra annotation, is that state objects are explicitly identified. E.g.; #StateObject, #ObservableObject. And you have to create reference type objects separate from your model. It essentially cuts out the middle man that is view model.
I think this is the most difficult thing for MVVM devs to get used to. You no longer need a view model to do what a view model does.
But shouldn't it be obvious? View model depends on how binding is designed. If SwiftUI has a binding design so efficient, (it does so declaratively without extra object) view model could be automatic.
SwiftUI removes UIViewController, does that mean you can't have Control?
I don't see MVC developers come out and create a Controller for every view.
Same reasoning, you can have MVVM without VM. Design pattern is a #State of mind.
To summarize:
I think the best architecture is official SDK. Learn to walk before you run.
MVVM in legacy sense is an option too. But I think you need to consider the possibility that
traditional wisdom is not up-to-date with latest SDK.
AFAIK view controller classes should be used for managing their views, IBActions, IBOutlets and other view-screen related stuff only. This means that view controller class should be as lightweight as possible, only concerning about managing its root and inner views. However, sometimes we are tempted to leave the code inside view controller class and not to move to other custom class.
Currently, I always create custom classes for models(database tables or custom objects), parser wrappers, heavy computations and for other logic that is more or less big and might be considered as a separate class. However, very frequently, I'm leaving some relative small computations, simple checking, simple download and other small code stuff inside view controller classes, because I'm lazy (and who is not?) and I'm not comfortable with having a bunch of tiny classes just because, theoretically, some several code statements does not belong to some view controller class. I understand that those tiny classes might evolve to bigger and real classes later, during other versions of an app, but however, might not.
IMHO, if you will be very concerned about the 100% pureness and cleanness you will spend more time (well, at least during initial versions of the app), but you will never know if the product will evolve or if it will be abandoned. There's always some trade-offs the developers are facing with.
It would be interesting to hear, what in-house rules do you use for designing your classes.
Two questions really that when/where you should do something which is whether you've stuck to the pattern or not.
And how
How is much less clear cut, particularly when practicality and pragmatism start getting in your face.
We tend to go for a static class for simple stuff e.g. a DateUtility class for parsing and formating dates in different formats.
And Aggregation for larger stuff, i.e. a downloader.
If you want reuse, decouple is the basic rule, so just because something was big wouldn't necessarily mean a different class.
Personally i like to have a strict class separation also if that means have a huge amount of files :(
Every object has its purpose and if i found some really generic operations i prefer create an "helper" class where encapsulate methods that cannot be specific of a context.
The really difficult step is to be strict on your decision and don't be lazy :) because by your question it's clear that you understand how it's important be rigorous on your code!
Say I want to create my view controller class with 2 superclasses; UIViewController and UIView.
is this possible? or is there another way of getting round this?
Multiple inheritance is not supported by Objective-C (hopefully, because multiple inheritance is generally synonym of bad design and also lead to potential complex problems like the diamond problem).
Use protocols instead if you need the concept of "common programming interface" (common API for multiple classes)
Note anyway that making a ViewController inherit UIView is nonsense anyway as this is not the same objects at all and in separate parts of the MVC pattern. (UIViewController being in the "Controller" part, probably holding behavior stuff, whereas UIView is the "View" part and not the Controller part, and only have to manage the display/visible representation of your stuff).
There is obviously some misunderstanding of the MVC pattern (omnipresent in Cocoa framework) and I suggest you take some time to read more about MVC. This may not be straightforward at the beginning if you are new to OOP but this is worth understanding as it would be easier for you once you understand it fully.
No multiple inheritance in Obj C. However you can achieve your goals using Protocols, composition and message forwarding. And might I add, just searching for the above 3 keywords in Apple's dev documentation pages is an excellent way to learn and get started.
One of the tasks of a view controller is to carry enough state so that the view can be released and rebuilt to handle low memory situations. So it is a likely a bad idea.
In general, the iOS framework uses delegates as a neat way to combine the behavior of 2 superclasses: you subclass one (or both) and have an instance of the other class as member variable. Neat and simple and probably a better design anyway.
The reason I ask is because I have separate domain objects which I map from the NSManagedObject subclasses so as to keep my data access logic separate.
But I think its going to be a problem for updating.
I wouldn't say that NSManagedObject subclasses must be passed to a controller object: In theory you could do what you're describing, and build a "front end" layer that sits between your Core Data model and your controllers – you're creating a lot more work, of course, and it might be just as easy to throw out your old model and start over, if and when you ever do decide to stop using Core Data.
You may also have to put more effort into keeping your model objects separate from your controller objects, what with a middle layer that could easily become a hodgepodge of both. It sounds like you've already gone down this road, though, so the question is probably more about the best use of your time and resources, and whether it's more cost-effective to phase out the middle layer or maintain it.
If you mean should you pass MySubclass vs NSManagedObject; it does not matter. The instance is what it is, your subclass. You can call it anything in between id and MySubclass.
So you can set up your controller to accept just an id or NSManagedObject you can pass it your subclass without an issue. If you want more exposed control to the subclass then you can pass around the subclass.
If that does not answer your question then I suggest you expound upon your question with an example.
Sticking to Apple's guidelines, I create one subclass of UIViewController per screen of my iPhone application. However I consistently find that these classes become very large, both in terms of sheer lines of code and number of member variables.
By definition they end up being responsible for quite a number of different concerns (e.g. view life cycle, mediating between views and models, sometimes touch handling, control logic, managing alerts and other UI state).
Not only does this violate the Single Responsibility Principle but it also results in large swathes of code which are near impossible to unit test.
What responsibilities/concerns do you tend to divide off into new classes? What kinds of responsibilities do you think make good candidates for clean separation in the case of UIViewController subclasses?
This is an interesting question and I also struggle on how to properly separate responsibility. It all depends on the context but since testing subclasses of UIVieController can be a pain I try to move as much as I can into model classes. In the spirit of Skinny Controller, Fat Model.
When it comes to tables I have created a base model class for handling all the table view stuff, basically encapsulating what you get when you create a new Navigation Based Core Data project. The in the controller I just forwards the calls to my table model.
I'm trying to keep the methods of the controller as small as possible. Depending on the context I may have several model classes, each responsible for a specific part.
I have also looked into the possibility of using controller factories for getting detail controllers for certain data models.
UIViewController *detailController = [self.controllerFactory controllerForItem:item];
[self presentModalViewController:detailController animated:YES];
This way I can unit test that I get the proper controller for a specific data item without having to involve the parent controller.
With mine, I'm creating categories, abstract parents and using a variety of patterns I've learned in the Java world to reduce complexity and code duplication. But when it comes down to it, I still have one view controller per screen because every screen has at least one thing on it thats unique in some way. There just might not be much code left in the controllers thanks to the infrastructure I've placed around them.