[Swift] MVC 모드로 Massive View Controller가 만든 부채 애플리케이션(개인 개발)을 팩스로 전송했습니다.
MassivewController 소개
기계 ViewController가 쉽다는 거 알아요?
ViewController가 지나치게 많은 기능을 로드하는 기능입니다.
수정의 계기
오랜만에 앱을 수정하려고 기세등등하게 발표했는데, 켜면 ViewController 1개가 장문의 글로 쓰여져 있어 유지보수성이 낮습니다.
며칠 전 MVC 모드(Swift) 샘플 기사도 기고한 바 있는데, 유지보수성이 더 높은 코드로 이전한 경험, 실제로 느낀 이점 등을 기재할 수 있으면 더 좋을 것 같아 이 기사를 쓰고 있다.
응용 프로그램 소개
쉽게 말하면 오프라인에서도 역할을 발휘할 수 있는'메모장 활용'이다.
수첩을 만들 때마다 수첩에 '클래스 이름' 을 설정할 수 있습니다.(갑판? 그게 뭐야?)
프로그램이 시작될 때 분류 일람표를 빠뜨리지 말고 반복해서 가져오십시오. 첫 페이지에 50음 순서로 배열하십시오.
이번에는 우선 그 화면을 팩스로 전송했다.
상기 이미지에는 분류 이름'공백'과'great'의 수첩이 존재하기 때문에 이런 화면이 되었다.
또한 각 칸을 누르면 화면 이동을 할 수 있다.
수정 전 화면에 설치된 기능
화면 왼쪽 상단의
UINavigationButton(ハンバーガーメニュー)
를 누르면 프로그램 라이브러리 SideMenu를 열고 다른 설정을 열 수 있습니다.프로그램이 시작될 때 이 화면이 열립니다.응용 프로그램에서 저장된 데이터를 읽고 표시합니다. (이 데이터는 응용 프로그램이 끝난 후에도 저장되며 다음 시작 후에도 저장하고 참조할 수 있습니다.)
수정 전 코드
이것은
Userdefault
의 학급 구성이다.기계 ViewController이기 때문에 xib 파일에 대상을 직접 설정하여
マシマシViewController
와 관련이 있습니다.또한 주처리는 모두
.swiftファイル
에 기재되었다.지루한 코드라 기사를 먼저 읽는 것을 추천해도 괜찮다.
FolderListViewController.Swift
import UIKit
import SafariServices
import SwiftReorder
import RxSwift
import RxCocoa
import SideMenu
import UIKit
import MessageUI
class FolderListViewController: UIViewController,SettingsDelegate,UIScrollViewDelegate, MFMailComposeViewControllerDelegate {
var dataManager = DataManager.shared
let disposeBag = DisposeBag()
var menuNavigationController: SideMenuNavigationController? = nil
var folderList = [String]()
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var bannerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
dataManager.loadColor()
setThemeColor()
dataManager.loadOriginalDataArray()
loadSettings()
loadNavigationController()
loadTableView()
UpgradeNotice.shared.fire()
AdMobHelper.shared.setupBannerAd(adBaseView: self.bannerView, rootVC: self)
AdMobHelper.shared.setupInterstitialAd(rootVC: self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "デッキカテゴリー 一覧"
self.tableView.reloadData()
self.getFolderList()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
APIRequest.getShareSheetData()
}
func getFolderList() {
var emptyList = [String]()
for (i,deckModel) in dataManager.deckList.enumerated() {
emptyList.append(deckModel.folderName)
}
let orderedSet:NSOrderedSet = NSOrderedSet(array: emptyList)
var folderUniqueList = orderedSet.array as! [String]
folderUniqueList.sort()
self.folderList = folderUniqueList
print(folderUniqueList)
print("並び替え終わり")
}
func loadSettings() {
let menuViewController = SettingsViewController()
menuViewController.delegate = self
//サイドメニューのナビゲーションコントローラを生成
menuNavigationController = SideMenuNavigationController(rootViewController: menuViewController)
//設定を追加
menuNavigationController!.settings = makeSettings()
// //左,右のメニューとして追加
SideMenuManager.default.leftMenuNavigationController = menuNavigationController
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .left)
}
//サイドメニューの設定
private func makeSettings() -> SideMenuSettings {
var settings = SideMenuSettings()
//動作を指定
settings.presentationStyle = .menuSlideIn
//メニューの陰影度
settings.presentationStyle.onTopShadowOpacity = 10.0
//ステータスバーの透明度
settings.statusBarEndAlpha = 0
return settings
}
func loadNavigationController() {
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.titleTextAttributes = [
// 文字の色
.foregroundColor: UIColor.white
]
var createBarButtonItem: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "menu_icon.png")!, style: .plain, target: self, action: #selector(settingBarButtonTapped(_:)))
self.navigationItem.leftBarButtonItems = [createBarButtonItem]
}
func loadTableView() {
tableView.separatorInset = .zero
tableView.isEditing = false
tableView.allowsSelectionDuringEditing = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ArchiveTableViewCell", bundle: nil), forCellReuseIdentifier: "ArchiveCell")
tableView.register(UINib(nibName: "DeckListTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.tableFooterView = UIView(frame: CGRect.zero)
}
func setThemeColor() {
self.navigationController?.navigationBar.barTintColor = dataManager.themeColor
self.tableView.reloadData()
loadSettings()
}
// 選択されたサイドバーのアイテムを取得
func tappedSettingsItem(indexpath: IndexPath) {
switch indexpath.row {
case SettingsMenu.openCreateDeckRecipeSite.rawValue:
let webPage = "https://www.pokemon-card.com/deck/deck.html"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
case SettingsMenu.backup.rawValue:
if MFMailComposeViewController.canSendMail()==false {
showSimpleAlertView(title: nil, message: "メールアプリが開けませんでした。", ButtonText: "OK")
return
}
var mailViewController = MFMailComposeViewController()
mailViewController.mailComposeDelegate = self
var backupmsg = ""
for deckModel in dataManager.deckList {
backupmsg += "デッキ名:" + deckModel.deckTitle + "\nデッキコード:" + deckModel.duckRecipeId + "\nメモ:" + deckModel.memo + "\n\n"
}
backupmsg += "\n\n【アーカイブされたデッキレシピ】\n"
for deckModel in dataManager.archiveDeckList {
backupmsg += "デッキ名:" + deckModel.deckTitle + "\nデッキコード:" + deckModel.duckRecipeId + "\nメモ:" + deckModel.memo + "\n\n"
}
mailViewController.setMessageBody(backupmsg, isHTML: false)
present(mailViewController, animated: true, completion: nil)
case SettingsMenu.changeThemeColor.rawValue:
let alertView = UIAlertController(
title: "テーマカラー:変更",
message: "\n\n\n\n\n\n\n\n\n",
preferredStyle: .alert)
let pickerView = UIPickerView(frame:
CGRect(x: 0, y: 50, width: 270, height: 162))
pickerView.dataSource = self
pickerView.delegate = self
// comment this line to use white color
pickerView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2)
alertView.view.addSubview(pickerView)
let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.default) { _ in
self.dataManager.saveColor()
AdMobHelper.shared.setupInterstitialAd(rootVC: self)
}
alertView.addAction(action)
present(alertView, animated: true, completion: {
pickerView.frame.size.width = alertView.view.frame.size.width
})
case SettingsMenu.Request.rawValue:
let webPage = "https://forms.gle/NecGPHqX9UZFALPdA"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
case SettingsMenu.Howtouse.rawValue:
showSimpleAlertView(title: nil, message: "デッキレシピ表示行(以下、行)を長押しして移動させると並び替えができます。\n\n行を左にスワイプすると「アーカイブ」できます。\n\nアーカイブされたデッキ一覧画面で行を左スワイプすると「元に戻す」「(デッキレシピ)削除」できます。\n\nデッキレシピ詳細画面で右上の共有ボタンを押すとツイートすることができます。\n\n詳細画面下部の「デッキレシピをサーバーにシェアする」を押すとサーバーにアップロードされ、トップ画面の「他のプレイヤーによってシェアされたデッキレシピ」から確認可能です。\n\nデッキ編集画面に「カテゴリー」を追加しました。こちらを変更して確定(反映)することでアプリのトップ画面でのデッキカテゴリーで分類されるようになります。", ButtonText: "OK")
case SettingsMenu.CheckUpdate.rawValue:
let webPage = "https://apps.apple.com/jp/app/%E3%83%9D%E3%82%B1%E3%82%AB%E3%83%87%E3%83%83%E3%82%AD%E7%AE%A1%E7%90%86/id1570965372"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
default:
break
}
}
@objc func settingBarButtonTapped(_ sender: UIBarButtonItem) {
present(menuNavigationController!, animated: true, completion: nil)
}
func showSimpleAlertView(title: String?,message: String, ButtonText: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction:UIAlertAction = UIAlertAction(title: ButtonText, style: .default, handler:{ (action:UIAlertAction!) -> Void in
alertController.dismiss(animated: true, completion: nil) // 閉じる
})
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
extension FolderListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (indexPath.row == self.folderList.count + 1) {
// シェアされたデッキレシピが押下された
let vc = ShareListViewController()
self.navigationController?.pushViewController(vc, animated: true)
} else if (indexPath.row == self.folderList.count) {
// アーカイブされたデッキレシピが押下された時
let vc = ArchiveListViewController()
self.navigationController?.pushViewController(vc, animated: true)
} else {
let listVC = ListViewController()
listVC.selectFolder = self.folderList[indexPath.row]
self.navigationController?.pushViewController(listVC, animated: true)
}
}
}
extension FolderListViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.folderList.count + 1 + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.row < self.folderList.count) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") else {
return UITableViewCell()
}
cell.textLabel?.text = folderList[indexPath.row]
return cell
}
if (indexPath.row == self.folderList.count) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ArchiveCell") as? ArchiveTableViewCell else {
return UITableViewCell()
}
cell.backgroundColor = dataManager.themeColor
cell.title?.text = "アーカイブされたデッキレシピ"
return cell
}
if (indexPath.row == self.folderList.count + 1) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ArchiveCell") as? ArchiveTableViewCell else {
return UITableViewCell()
}
cell.backgroundColor = dataManager.themeColor
cell.title?.text = "他のプレイヤーによってシェアされたデッキレシピ"
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none //表示させない。
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false //ずれない。
}
}
extension FolderListViewController: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dataManager.colorList.count
}
}
extension FolderListViewController: UIPickerViewDelegate {
// UIPickerViewに表示する配列
func pickerView(_ pickerView: UIPickerView,
titleForRow row: Int,
forComponent component: Int) -> String? {
return String(dataManager.colorList[row])
}
// UIPickerViewのRowが選択された時の挙動
func pickerView(_ pickerView: UIPickerView,
didSelectRow row: Int,
inComponent component: Int) {
switch row {
case ThemeColor.themeGrass.rawValue:
dataManager.themeColor = UIColor.rgba(red: 60, green: 179, blue: 113, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeFire.rawValue:
dataManager.themeColor = UIColor.rgba(red: 203, green: 86, blue: 70, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeWater.rawValue:
dataManager.themeColor = UIColor.rgba(red: 0, green: 191, blue: 255, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeLightning.rawValue:
dataManager.themeColor = UIColor.rgba(red: 255, green: 215, blue: 0, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themePsychic.rawValue:
dataManager.themeColor = UIColor.rgba(red: 255, green: 105, blue: 180, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeFighting.rawValue:
dataManager.themeColor = UIColor.rgba(red: 210, green: 105, blue: 30, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeDarkness.rawValue:
dataManager.themeColor = UIColor.rgba(red: 25, green: 25, blue: 112, alpha: 0.8)
setThemeColor()
break
case ThemeColor.themeMetal.rawValue:
dataManager.themeColor = UIColor.rgba(red: 192, green: 192, blue: 192, alpha: 1.0)
setThemeColor()
break
default:
break
}
}
}
개수에 대하여 개수 전의 문제점을 조사하다
FolderListViewController.Swift
에도 공동 처리 가능한 내용이 기재되어 있다.)FolderListViewController.Swift
와 PickerViewの処理
가 모두 기재되어 있다.MVC 모드를 위한 수정 사항
우선 MVC 모드를 개작해 뷰의 묘사
UITableViewDelegate,UITableViewDatasource
, 비즈니스 로직의 처리View部分
를 분리해 날씬화를 목표로 한다.또한 다른 화면의 중복 처리는 원류를 계승하는
Model部分
을 만들고 모든 일람에 나타난 화면에서 상기 종류를 계승한다.우리 반에 기재되지 않은 것은 화면에 존재하는 처리뿐이다.예를 들어 전체 화면을 사용하지 않지만 두 화면의 기능만 사용하는 경우 댓글에 알기 쉽게 기재된다.
또한 본 글의 원본 코드에는 나타나지 않았지만 다음과 같은 종류의 처리가 존재합니다.
FolderListModel.swift(Model)
import Foundation
class FolderListModel: NSObject,UITableViewDataSource {
// シングルトンクラス
var dataManager = DataManager.shared
// Modelを監視するクラス
let notificationCenter = NotificationCenter()
// カテゴリー名(文字列)を管理する配列。この配列を元に表示を行う。
private(set) var folderNameList: [String] = [
] {
didSet{
// Modelで管理している配列に変化があった場合に呼び出されて、通知する。
notificationCenter.post(name: .init(rawValue: "changeFolderNameList"), object: nil, userInfo: ["list" : folderNameList])
}
}
// MARK: logic
// 最新の値を取得してTableViewを更新する
func reacquisitionListAndReloadTableView(tableView: UITableView) {
self.getCategoryFilterdDeckList()
tableView.reloadData()
}
// カテゴリーを漏れなく抜けなく取り出して、表示する
func getCategoryFilterdDeckList() {
var emptyList = [String]()
for (i,deckModel) in dataManager.deckList.enumerated() {
emptyList.append(deckModel.folderName)
}
let orderedSet:NSOrderedSet = NSOrderedSet(array: emptyList)
var folderUniqueList = orderedSet.array as! [String]
folderUniqueList.sort()
self.folderNameList = folderUniqueList
}
// MARK: UITableViewDatasoruce
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 「アーカイブされたデッキレシピ」「他のプレイヤーによってシェアされたデッキレシピ」
return self.folderNameList.count + 1 + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.row < self.folderNameList.count) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") else {
return UITableViewCell()
}
let deckModel: String = self.folderNameList[indexPath.row]
cell.textLabel?.text = deckModel
return cell
}
if (indexPath.row == self.folderNameList.count) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ArchiveCell") as? ArchiveTableViewCell else {
return UITableViewCell()
}
cell.backgroundColor = dataManager.themeColor
cell.title?.text = "アーカイブされたデッキレシピ"
return cell
}
if (indexPath.row == self.folderNameList.count + 1) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ArchiveCell") as? ArchiveTableViewCell else {
return UITableViewCell()
}
cell.backgroundColor = dataManager.themeColor
cell.title?.text = "他のプレイヤーによってシェアされたデッキレシピ"
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none //表示させない。
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false //ずれない。
}
}
모델 부분은 책임BaseListViewController.swift
의 처리로 변경되었다.셀의 표시 수와 컨텐트를 표시할 때는 셀의 표시 컨텐트(배열)를 유지하는 Model 섹션을 사용하는 것이 좋다고 생각합니다.
적어도 Controller는 모델과View 사이의 다리를 관철해야 하기 때문에 나는 이 설계에 문제가 없다고 생각한다.
Model 처리
UITableViewDataSource
방법 등을 Controller 섹션에 기재합니다.FolderListView.swift(View 부분)
import Foundation
import UIKit
class FolderListView: UIView {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var bannerView: UIView!
override init(frame: CGRect){
super.init(frame: frame)
loadNib()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
loadNib()
}
func loadNib(){
let view = Bundle.main.loadNibNamed("FolderListView", owner: self, options: nil)?.first as! UIView
view.frame = self.bounds
self.addSubview(view)
}
}
UITableViewDataSource
새로 만들 때만 만드십시오FolderListView.xib
, 제작 후 View
와 연결하십시오(제작 시 미리 연결할 수 없습니다)그림을 참고하여 진행하세요.
FolderListViewController.swift(Controller 섹션)
import UIKit
import SafariServices
import SwiftReorder
import RxSwift
import RxCocoa
import SideMenu
import UIKit
import MessageUI
class FolderListViewController: BaseListViewController,UIScrollViewDelegate {
var myModel: FolderListModel? {
// セットされるたびにdidSetが動作する
didSet {
// ViewとModelとを結合し、Modelの監視を開始する
registerModel()
}
}
// MARK: Lifecycle
override func loadView() {
super.loadView()
self.view = FolderListView()
}
override func viewDidLoad() {
super.viewDidLoad()
prepareViewController()
self.myModel = FolderListModel()
// インスタンス生成直後なのでクラッシュの可能性が低く、gurad letを利用しない。
self.myModel!.getCategoryFilterdDeckList()
// サイドメニュー
settingSideMenu()
settingNavigationController()
// アップデートを確認する。
UpgradeNotice.shared.fire()
let folderListView = self.view as! FolderListView
guard let myModel = self.myModel else { return }
settingTableView(tableView: folderListView.tableView, delegate: self, datasource: myModel)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "デッキカテゴリー 一覧"
let folderListView = self.view as! FolderListView
guard let model = myModel else { return }
model.reacquisitionListAndReloadTableView(tableView: folderListView.tableView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
APIRequest.getShareSheetData()
}
// サブメニューを表示する処理
@objc override func settingBarButtonTapped(_ sender: UIBarButtonItem) {
present(menuNavigationController!, animated: true, completion: nil)
}
// 継承元クラス setThemeColor:で色変更の処理を行い、追加で継承先の本クラスでテーブルビューを更新する処理を走らせる。
override func setThemeColor() {
super.setThemeColor()
let folderListView = self.view as! FolderListView
self.reloadTableView(tableView: folderListView.tableView)
}
private func registerModel() {
guard let model = myModel else { return }
// 配列が変化したらnotificationCenterで通知を受け取る。
model.notificationCenter.addObserver(forName: .init(rawValue: "changeFolderNameList"),
object: nil,
queue: nil,
using: {
[unowned self] notification in
let folderListView = self.view as! FolderListView
folderListView.tableView.reloadData()
})
}
}
extension FolderListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let myModel = self.myModel else { return }
if (indexPath.row == myModel.folderNameList.count + 1) {
// シェアされたデッキレシピが押下された
let vc = ShareListViewController()
self.navigationController?.pushViewController(vc, animated: true)
} else if (indexPath.row == myModel.folderNameList.count) {
// アーカイブされたデッキレシピが押下された時
let vc = ArchiveListViewController()
self.navigationController?.pushViewController(vc, animated: true)
} else {
let listVC = ListViewController()
listVC.selectFolder = myModel.folderNameList[indexPath.row]
self.navigationController?.pushViewController(listVC, animated: true)
}
}
}
BaseListViewController.swift (상속자의 반)
어떻게 처리해도 많아서 코드량이 많아졌어요.
다른 부분의 중복된 코드는 한 종류에만 기재된다
방법이 있겠지.
import UIKit
import SafariServices
import SwiftReorder
import RxSwift
import RxCocoa
import SideMenu
import UIKit
import MessageUI
class BaseListViewController: UIViewController, SettingsDelegate, MFMailComposeViewControllerDelegate {
// シングルトンクラス
var dataManager = DataManager.shared
// サイドメニュー
var menuNavigationController: SideMenuNavigationController? = nil
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: AdMob
// AdMobにバナー広告をリクエストする処理
func requestAdMobOfBannerAd (bannerView: UIView) {
AdMobHelper.shared.setupBannerAd(adBaseView: bannerView, rootVC: self)
AdMobHelper.shared.setupInterstitialAd(rootVC: self)
}
// AdMobに全画面広告をリクエストする処理
func requestAdMobOfInterstitialAd () {
AdMobHelper.shared.setupInterstitialAd(rootVC: self)
}
// MARK: データマネージャ(シングルトン)にアクセスする処理
func prepareDataManagerForShowData() {
dataManager.loadColor()
dataManager.loadOriginalDataArray()
}
// MARK: 汎用的な一覧画面で行われる処理
// TableViewを更新する(テーマカラー更新後などもこちらのメソッドを呼び出す)
func reloadTableView (tableView: UITableView) {
tableView.reloadData()
}
// 全画面で共通しているデザインなどの画面の準備
func prepareViewController() {
dataManager.loadColor()
dataManager.loadOriginalDataArray()
setThemeColor()
settingNavigationController()
}
// TableViewで必要な設定を行う。Delegate,DataSourceは各ViewControllerでself,Modelを設定する
func settingTableView(tableView: UITableView, delegate:NSObject,datasource: NSObject) {
tableView.separatorInset = .zero
tableView.isEditing = false
tableView.allowsSelectionDuringEditing = true
tableView.delegate = delegate as! UITableViewDelegate
tableView.dataSource = datasource as! UITableViewDataSource
tableView.register(UINib(nibName: "ArchiveTableViewCell", bundle: nil), forCellReuseIdentifier: "ArchiveCell")
tableView.register(UINib(nibName: "DeckListTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.tableFooterView = UIView(frame: CGRect.zero)
}
// シンプルなAlertViewを表示する共通処理
func showSimpleAlertView(title: String?,message: String, ButtonText: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction:UIAlertAction = UIAlertAction(title: ButtonText, style: .default, handler:{ (action:UIAlertAction!) -> Void in
alertController.dismiss(animated: true, completion: nil) // 閉じる
})
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
// カラーを設定する
func setThemeColor() {
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = dataManager.themeColor
navigationController?.navigationBar.standardAppearance = appearance
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
navigationController?.navigationBar.barTintColor = dataManager.themeColor
}
}
// MARK: SideMenuが表示されているフォルダ一覧、デッキ一覧で表示する処理
// FolderListViewControllerでサブメニューを表示する処理
@objc func settingBarButtonTapped(_ sender: UIBarButtonItem) {
}
func settingSideMenu() {
let menuViewController = SettingsViewController()
menuViewController.delegate = self
//サイドメニューのナビゲーションコントローラを生成
menuNavigationController = SideMenuNavigationController(rootViewController: menuViewController)
//設定を追加
menuNavigationController!.settings = makeSettings()
// //左,右のメニューとして追加
SideMenuManager.default.leftMenuNavigationController = menuNavigationController
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = dataManager.themeColor
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
SideMenuManager.default.leftMenuNavigationController?.navigationBar.scrollEdgeAppearance = appearance
SideMenuManager.default.leftMenuNavigationController?.navigationBar.standardAppearance = appearance
} else {
navigationController?.navigationBar.barTintColor = dataManager.themeColor
}
SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: self.view, forMenu: .left)
}
//サイドメニューの設定
private func makeSettings() -> SideMenuSettings {
var settings = SideMenuSettings()
//動作を指定
settings.presentationStyle = .menuSlideIn
//メニューの陰影度
settings.presentationStyle.onTopShadowOpacity = 10.0
//ステータスバーの透明度
settings.statusBarEndAlpha = 0
return settings
}
// NavigationBarItemを設定する
func settingNavigationController() {
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.titleTextAttributes = [
// 文字の色
.foregroundColor: UIColor.white
]
var createBarButtonItem: UIBarButtonItem =
UIBarButtonItem(image: UIImage(systemName: "list.bullet")!, style: .plain, target: self, action: #selector(settingBarButtonTapped(_:)))
self.navigationItem.leftBarButtonItems = [createBarButtonItem]
}
// 選択されたサイドバーのアイテムを取得
func tappedSettingsItem(indexpath: IndexPath) {
switch indexpath.row {
case SettingsMenu.openCreateDeckRecipeSite.rawValue:
let webPage = "https://www.pokemon-card.com/deck/deck.html"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
case SettingsMenu.backup.rawValue:
if MFMailComposeViewController.canSendMail()==false {
showSimpleAlertView(title: nil, message: "メールアプリが開けませんでした。", ButtonText: "OK")
return
}
var mailViewController = MFMailComposeViewController()
mailViewController.mailComposeDelegate = self
var backupmsg = ""
for deckModel in dataManager.deckList {
backupmsg += "デッキ名:" + deckModel.deckTitle + "\nデッキコード:" + deckModel.duckRecipeId + "\nメモ:" + deckModel.memo + "\n\n"
}
backupmsg += "\n\n【アーカイブされたデッキレシピ】\n"
for deckModel in dataManager.archiveDeckList {
backupmsg += "デッキ名:" + deckModel.deckTitle + "\nデッキコード:" + deckModel.duckRecipeId + "\nメモ:" + deckModel.memo + "\n\n"
}
mailViewController.setMessageBody(backupmsg, isHTML: false)
present(mailViewController, animated: true, completion: nil)
case SettingsMenu.changeThemeColor.rawValue:
let alertView = UIAlertController(
title: "テーマカラー:変更",
message: "\n\n\n\n\n\n\n\n\n",
preferredStyle: .alert)
let pickerView = UIPickerView(frame:
CGRect(x: 0, y: 50, width: 270, height: 162))
pickerView.dataSource = self
pickerView.delegate = self
// comment this line to use white color
pickerView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2)
alertView.view.addSubview(pickerView)
let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.default) { _ in
self.dataManager.saveColor()
AdMobHelper.shared.setupInterstitialAd(rootVC: self)
}
alertView.addAction(action)
present(alertView, animated: true, completion: {
pickerView.frame.size.width = alertView.view.frame.size.width
})
case SettingsMenu.Request.rawValue:
let webPage = "https://forms.gle/NecGPHqX9UZFALPdA"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
case SettingsMenu.Howtouse.rawValue:
showSimpleAlertView(title: nil, message: "デッキレシピ表示行(以下、行)を長押しして移動させると並び替えができます。\n\n行を左にスワイプすると「アーカイブ」できます。\n\nアーカイブされたデッキ一覧画面で行を左スワイプすると「元に戻す」「(デッキレシピ)削除」できます。\n\nデッキレシピ詳細画面で右上の共有ボタンを押すとツイートすることができます。\n\n詳細画面下部の「デッキレシピをサーバーにシェアする」を押すとサーバーにアップロードされ、トップ画面の「他のプレイヤーによってシェアされたデッキレシピ」から確認可能です。\n\nデッキ編集画面に「カテゴリー」を追加しました。こちらを変更して確定(反映)することでアプリのトップ画面でのデッキカテゴリーで分類されるようになります。", ButtonText: "OK")
case SettingsMenu.CheckUpdate.rawValue:
let webPage = "https://apps.apple.com/jp/app/%E3%83%9D%E3%82%B1%E3%82%AB%E3%83%87%E3%83%83%E3%82%AD%E7%AE%A1%E7%90%86/id1570965372"
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
safariVC.modalPresentationStyle = .fullScreen
present(safariVC, animated: true, completion: nil)
default:
break
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
// MARK: PickerView
extension BaseListViewController: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dataManager.colorList.count
}
}
extension BaseListViewController: UIPickerViewDelegate {
// UIPickerViewに表示する配列
func pickerView(_ pickerView: UIPickerView,
titleForRow row: Int,
forComponent component: Int) -> String? {
return String(dataManager.colorList[row])
}
// UIPickerViewのRowが選択された時の挙動
func pickerView(_ pickerView: UIPickerView,
didSelectRow row: Int,
inComponent component: Int) {
switch row {
case ThemeColor.themeGrass.rawValue:
dataManager.themeColor = UIColor.rgba(red: 60, green: 179, blue: 113, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeFire.rawValue:
dataManager.themeColor = UIColor.rgba(red: 203, green: 86, blue: 70, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeWater.rawValue:
dataManager.themeColor = UIColor.rgba(red: 0, green: 191, blue: 255, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeLightning.rawValue:
dataManager.themeColor = UIColor.rgba(red: 255, green: 215, blue: 0, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themePsychic.rawValue:
dataManager.themeColor = UIColor.rgba(red: 255, green: 105, blue: 180, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeFighting.rawValue:
dataManager.themeColor = UIColor.rgba(red: 210, green: 105, blue: 30, alpha: 1.0)
setThemeColor()
break
case ThemeColor.themeDarkness.rawValue:
dataManager.themeColor = UIColor.rgba(red: 25, green: 25, blue: 112, alpha: 0.8)
setThemeColor()
break
case ThemeColor.themeMetal.rawValue:
dataManager.themeColor = UIColor.rgba(red: 192, green: 192, blue: 192, alpha: 1.0)
setThemeColor()
break
default:
break
}
}
}
잡담
NavigationBar의 배경색이 투명해지는 것에 대해 Xcode13(iOS 15)이 있기 때문에 그곳의 일은 수정 중이다.
팩스의 장점
상당히 크다.
원래는 Massiveview Controller로 썼어요.
MVC 모드로 쓰는 게 익숙하지 않다고 할 수 있다.
당초 MVC 모드를 만들 때마다 그 자체로 에너지를 소모할 예정이었지만 그런 일은 없었다.
그러나 Model-View-Ctroller 클래스를 유사하게 복사합니다.
각자의 책임과 의무로 나뉘어 각자 기재 처리를 하면 길고 가는 코드가 되어 효율적으로 진행할 수 있고 팩스 조작에 시간이 걸리지 않는다.
Reference
이 문제에 관하여([Swift] MVC 모드로 Massive View Controller가 만든 부채 애플리케이션(개인 개발)을 팩스로 전송했습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/tanukidevelop/articles/1cc2bbcae5b4f4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)