Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

iOSAppArchitecture

iOS app architecture we use.

MVPCF = Model View Presenter Coordinator Factory;

It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;

SOLID principles are the core of our architecture.

For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.

1. For assembling project we use DI pattern with Swinject library.

App has shared Container where we register all shared dependencies we need to use across the whole app.

2. Project is divided up into Flows

Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.

This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.

Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.

Coordinator builds the screens (Modules) and controls the flow.

The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.

3. Every Module for example has the following structure:

Factory

Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!

protocol<Name>Factory {func make()-><Name>Routes
}

Routes

Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.

protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}

Presenter

Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.

// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}

View

Abstraction for view. It has default implementation inherited from UIView.

It contains custom view for ViewController.

protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}

ViewController

Inherired from UIViewController Implements Routes protocol.

It is responsible for:

  • binding Presenter to View;
  • registering for events as a button tap;
  • firing Routes closures. Basically it is the main building structure of screens.

4. Every Presenter's implementation injects dependencies it needs.

classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}

Every dependency should have only one responsibility!

For example:

protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}

Or this:

protocolFirstLaunchManager{func performTasksOnFirstLaunch()}

Or this:

protocolLogoutManager{func logout()}

5. Differences from the other architectures.

  • MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;

  • VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.

  • RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.

About

iOS app architecture we use. Feel free to contribute.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages