Skip to content

Commit

Permalink
Merge pull request #37 from p-x9/feature/delegate
Browse files Browse the repository at this point in the history
Delegate
  • Loading branch information
p-x9 authored Mar 15, 2023
2 parents a7045dd + 2f3510f commit d770def
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 1 deletion.
13 changes: 12 additions & 1 deletion Example/Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class ViewController: UIViewController {
setupViews()
setupViewConstraints()
setupNavigationItems()

appContainer.delegates.add(self)
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -285,7 +287,7 @@ extension ViewController {
print("container will change")
}

let didChangeObservation = notificationCenter.addObserver(forName: AppContainer.containerWillChangeNotification, object: nil, queue: .current) { _ in
let didChangeObservation = notificationCenter.addObserver(forName: AppContainer.containerDidChangeNotification, object: nil, queue: .current) { _ in
print("container did change")
}

Expand All @@ -299,6 +301,15 @@ extension ViewController {
}
}

extension ViewController: AppContainerDelegate {
func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?) {
print(#function, (fromContainer?.name ?? "") + " -> " + (toContainer.name ?? ""))
}

func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?) {
print(#function, (fromContainer?.name ?? "") + " -> " + (toContainer.name ?? ""))
}
}

extension ViewController {
class View: UIView {
Expand Down
43 changes: 43 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,49 @@ try AppContainer.standard.cleanContainer(uuid: uuid)
try AppContainer.standard.reset()
```

### 通知(Notification)
コンテナ切り替え時に通知を受け取ることができます。
厳密に、切り替え前および切り替え後に行いたい処理を追加する場合は、後述するdelegateを使用してください。

- containerWillChangeNotification
コンテナ切り替え前
- containerDidChangeNotification
コンテナ切り替え後
### 委譲(Delegate)
Delegateを使用して、コンテナの切り替え時に、任意の処理を追加することができます。
以下の順で処置が行われます。

``` swift
// `activate`メソッドが呼び出される

// ↓↓↓↓↓↓↓↓↓↓


func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?) // Delegate(コンテナ切り替え前)

// ↓↓↓↓↓↓↓↓↓↓

// コンテナの切り替え処理(ライブラリ)

// ↓↓↓↓↓↓↓↓↓↓

func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?) // Delegate(コンテナ切り替え後)
```

このライブラリでは複数のdelegateを設定できるようになっています。
以下のように追加します。
```swift
AppContainer.standard.delegates.add(self) // selfがAppContainerDelegateに準拠している場合
```
弱参照で保持されており、オブジェクトが解放された場合は自動で解除されます。
もし、delegateの設定を解除したい場合は以下のように書きます。
```swift
AppContainer.standard.delegates.remove(self) // selfがAppContainerDelegateに準拠している場合
```

### AppContainerUI
AppContainerを扱うためのUIを提供しています。
SwiftUIおよびUIKitに対応しています。
#### SwiftUI
```swift
import AppContainerUI
Expand Down
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,48 @@ Specifically, the DEFAULT container will be enabled and all other AppContainer-r
try AppContainer.standard.reset()
```

### Notification
You can receive notifications when switching containers.
If you want to add additional processing to be done strictly before and after the switch, use delegate as described below.

- containerWillChangeNotification
Before container switching
- containerDidChangeNotification
After container change

### Delegate
Delegate can be used to add optional processing when switching containers.
The actions are performed in the following order.

``` swift
// the `activate` method is called

// ↓↓↓↓↓↓↓↓↓↓


func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?) // Delegate(before container switch)

// ↓↓↓↓↓↓↓↓↓↓

// Container switching process (library)

// ↓↓↓↓↓↓↓↓↓↓

func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?
```

This library allows multiple delegates to be set.
Add the following.

```swift
AppContainer.standard.delegates.add(self) // if self is AppContainerDelegate compliant
```
It is held in a weak reference and will be automatically released when the object is freed.
If you want to unset the delegate, write the following.
```swift
AppContainer.standard.delegates.remove(self) // if self conforms to AppContainerDelegate
```

### AppContainerUI
#### SwiftUI
```swift
Expand Down
10 changes: 10 additions & 0 deletions Sources/AppContainer/AppContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class AppContainer {
/// standard container manager
public static let standard = AppContainer()

public var delegates: WeakHashTable<AppContainerDelegate> = .init()

private let fileManager = FileManager.default

private let notificationCenter = NotificationCenter.default
Expand Down Expand Up @@ -103,7 +105,12 @@ public class AppContainer {
return
}

let fromContainer = self.activeContainer

notificationCenter.post(name: Self.containerWillChangeNotification, object: nil)
delegates.objects.forEach {
$0.appContainer(self, willChangeTo: container, from: fromContainer)
}

try exportUserDefaults()
exportCookies()
Expand All @@ -125,6 +132,9 @@ public class AppContainer {
try? updateInfo(of: container, keyValue: .init(\.lastActivatedDate, Date()))

notificationCenter.post(name: Self.containerDidChangeNotification, object: nil)
delegates.objects.forEach {
$0.appContainer(self, didChangeTo: container, from: fromContainer)
}
}

/// activate selected container
Expand Down
19 changes: 19 additions & 0 deletions Sources/AppContainer/AppContainerDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// AppContainerDelegate.swift
//
//
// Created by p-x9 on 2023/03/06.
//
//

import Foundation

public protocol AppContainerDelegate: AnyObject {
func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?)
func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?)
}

extension AppContainerDelegate {
public func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?) {}
public func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?) {}
}
47 changes: 47 additions & 0 deletions Sources/AppContainer/Util/WeakHashTable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// WeakHashTable.swift
//
//
// Created by p-x9 on 2023/03/10.
//

import Foundation

public class WeakHashTable<T> {
public var objects: [T] {
accessQueue.sync { _objects.allObjects.compactMap { $0 as? T } }
}

private var _objects: NSHashTable<AnyObject> = NSHashTable.weakObjects()
private let accessQueue: DispatchQueue = DispatchQueue(label:"com.p-x9.appcintainer.WeakHashTable.\(T.self)",
attributes: .concurrent)

public init() {}

public init(_ objects: [T]) {
for object in objects {
_objects.add(object as AnyObject)
}
}

public func add(_ object: T?) {
accessQueue.sync(flags: .barrier) {
_objects.add(object as AnyObject)
}
}

public func remove(_ object: T?) {
accessQueue.sync(flags: .barrier) {
_objects.remove(object as AnyObject)
}
}
}


extension WeakHashTable : Sequence {
public typealias Iterator = Array<T>.Iterator

public func makeIterator() -> Iterator {
return objects.makeIterator()
}
}

0 comments on commit d770def

Please sign in to comment.