I have a simple master-detail setup with two table view controllers. In the master controller I created a custom class, and I would like to work with this custom class in my detail controller. Now I know swift has done away with implementing classes, but when I try to create a new object of this class in my detail controller, it goes as "undeclared". Should there be an import statement? or am I missing something? here is a preview of the code in my master:
import UIKit
class FirstTableViewController: UITableViewController {
class Continent {
var name: String = "Country name"
var continentCountry: ["countries of selected continent"]
}
}
If you're trying to access Continent you'd need to prefix it with FirstTableViewController:
let continent = FirstTableViewController.Continent()
Take a look at The Swift Programming Language: Nested Types for more information.
Related
Do you guys know if it's possible to use a Swift nested class as UIViewController in Storyboard?
I'm looking into different ways to structure my projects, one of which is grouping related classes by nesting them in the same main class.
Let me explain with an example:
Say I have a screen for displaying my app's settings which needs a UIViewController and a model.
I could create 2 classes: SettingsController and SettingsModel, but I'm wondering if it wouldn't be nice to have it structured otherwise by having a main class Settings containing nested classes Controller and Model like so
class Settings {
class Controller: UIViewController {
...
}
class Model {
...
}
}
That way I could use them by doing Settings.Controller and Settings.Model which I think would look pretty nice.
Now this works fine expect when using storyboard. In Storyboard when I select a view controller to set the custom class, if I type in Setting.Controller and hit enter, the field does not validate and is cleared.
So my question is do you guys know what I'm doing wrong or if this is simply not possible?
Of course, it's after having posted the question that I found a solution so I'm sharing it for posterity.
So there was 1 problem to the way I was trying to do it:
Nested classes are references by using the dot
notation: Settings.Controller but Interface Builder does not
see that as a valid class name
The solution was simple, give the controller it's own Objc name:
class Settings {
#objc(SettingsController)
class Controller: UIViewController {
}
...
}
By doing this you give the nested controller an ObjC name thereby exposing it the Interface Builder. Now you can reference the controller by filling in SettingsController.
I don't think storyboards supports that (yet), so in the meantime you need to use some workarounds.
If all you want is the syntax Settings.Controller, you can do this: (Inspired by this answer)
Declare your Settings.Controller class not as a nested class, but as a standalone class SettingsController:
class SettingsController : UIViewController { ... }
Then in Settings, add a typealias:
class Settings {
typelias Controller = SettingsController
class Model { ... }
}
Now you can use SettingsController in the storyboard, but Settings.Controller in code.
Working sample available at: https://gitlab.com/nipunrd_git/mvvmarch
I am in process of migrating an app from MVC to MVVM. As far as I have read, you need to make your viewController independent of the Model, there by making a viewModel to glue the model and the controller together.
If we consider a simple screenA which has a refresh button to get some data via a web service and then fill the data in the view:
ScreenAViewController.swift: Will contain the code to hit the web service via a singleton network helper class.
ScreenA -> NetworkHandler -> fetchData
In order to make ScreenA, use the fetched data, we should now make a ViewModel, so I made ScreenAViewModel. Let's say our model was named "Design":
struct Design{
var pattern: String
}
Now our ViewModel would look like this:
class ScreenAViewModel{
private let design: Design
public let pattern: String
init (design: Design, pattern: String){
self.design = design
self.pattern = design.pattern
}
}
When we get the data from the web service, we should first create a Design model and then initialize our ViewModel with that. This ViewModel will now be used by our view controller to fetch and display data from. Any Business logic will be written in this only.
Is there a way to shift #3 to the view model itself? I think by having this conversion from model to viewModel in the controller itself is beating the purpose of hiding model from controller.
I'm relatively new to iOS development but have significant experience in Android/Java/Kotlin. So I tend to structure my ios projects a bit similar to my Android ones. So the basic structure I use is
class MyViewController: UIViewController{
private let viewModel = ViewModel()
}
class ViewModel{
func doSomethingAsync(delegate){
SomeFactory.createService().doSomethingAsync(){
delegate.callback
}
}
}
class SomeFactory{
static func createService() -> Service {return ServiceImpl()}
}
class Service{
func doSomething()
}
class ServiceImpl : Service{
func doSomething(){... implementation...}
}
So the view controller doesn't know anything about the business logic or services and all it sees are data models. The view model provides the bridging between the two. Also, no one can see the ServiceImpl class and is only accessible via the factory. Is this design over the top or is it too "javaish" for ios? How do people usually separate their view logic with the service/business logic of an app?
In viewController
Update your UI elements.
With out ui element updation everything’s (business logics) surely move to viewModel
Let's say I have a Car object with standard attributes like color, model, brand, and number of seats.
Each view controller in my app would be responsible for getting each of those attributes until the end:
Color View Controller --> Model View Controller --> Brand View Controller --> Seats Controller --> Result Controller
The way I pass data between each controller right now is through a Singleton, but I've read online that is is an anti-pattern and creates a lot of coupling later. Question is then: what is the best way for me to funnel all of the data to Result Controller?
Try to modify your singletons to services.
For example: your singleton StateManager has two method: set(state: SomeState) and getState() -> State.
First, use protocols:
protocol StateManager: class {
func set(state: SomeState)
func getStatus() -> SomeState
}
Second, your app modules shouldn't know about witch StateManager they use:
class MyAppController: UIViewController {
var stateManager: StateManager?
...
}
And when you init your VC:
let vc = MyAppController()
vc.stateManager = ConcreteStateManager.sharedInstance
//present vc
If you have a centralized place for create VC, you can hold instance of ConcreteStateManager in it, without calling sharedInstance.
Also, read about Dependency injection in swift.
I have some 10 API URLs like login,signup,forgotpassword,displaydata,mapcalling.php's urls.
Now I will create some view controller class to declare all the URL.
Like say, I am in my loginviewcontroller.swift class.Now here I need to call login.php URL to validate the username & password and allow user to enter to app.Like this we will call each API URL to all view controller.swift file classes.
So what my doubt is:
It's possible to create one separate file or class and declare all the API in that single file. Like:
let link1 = "url"
let link2 = "url"
let link3 = "url"
let link4 = "url"
let link5 = "url"
And call the needed URL to other view controller, by calling the declared object names. Like say, in my loginviewcontroller.swift file if we need to call my login.php URL.
Instead of calling the URL I need to call link1 to my loginviewcontroller.swift file.
How do I code in that separate class and how can I import that header to my other view controller for using the URL object name?
If I understand your question, you can create a Swift class that serves as a facade for your server. In that way, any of your controllers can access functions in the class as if they were talking to the server.
For example:
class ServerAccess {
static let link1 = "url1"
static func sendLoginRequest() {
print(link1)
}
}
Since it's Swift, you don't need imports, just reference the class in your controller as needed. (If the ServerAccess class needs to maintain state, it can be a shared instance instead of using class methods.)
ServerAccess.sendLoginRequest()