Closed7
『よくわかるAuto Layout』をXcode 13.3で動くようにする
Xcode 13.3用の修正手順
$ mkdir auto_layout
$ cd auto_layout
$ mv /path/to/1032_src.zip .
$ unzip 1032_src.zip
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=t&id=18wNfS34mfs1W0l2aKcMlARYQyDVu27zI" -o "xcode13.3.patch"
$ patch -p1 < xcode13.3.patch
Swiftのバージョンを指定する。
以下、上記手順に至るまでのメモなので、読む必要はないです。
XCodeは13.3を使用。
とりあえずSwiftのバージョン指定がないので直す。
Value for SWIFT_VERSION cannot be empty.
Build Settings
のSwift Compiler - Language
のSwift Language Version
をSwift 5
に変更。
Debug用のコードを修正。
/AutoLayoutBookSampler/Timer.swift b/AutoLayoutBookSampler/Timer.swift
@@ -11,9 +11,9 @@ import UIKit
class Timer: NSObject {
static let sharedInstance = Timer()
- private var startTime: NSDate?
+ private var startTime: Date?
func start() {
- startTime = NSDate()
+ startTime = Date()
}
func elapsedTime() {
@@ -22,7 +22,7 @@ class Timer: NSObject {
return
}
- let elapsedTime = NSDate().timeIntervalSinceDate(time) as Double
+ let elapsedTime = Date().timeIntervalSince(time)
print("経過時間:\(elapsedTime)")
}
Chapter 4の修正
/AutoLayoutBookSampler/Ch4/XibAndStoryboard.swift
@@ -24,15 +24,15 @@ class XibAndStoryboard: UIView {
}
func commonInit() {
- NSBundle.mainBundle().loadNibNamed("XibAndStoryboard", owner: self, options: nil)
+ Bundle.main.loadNibNamed("XibAndStoryboard", owner: self)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.contentView)
// 親ビューの四隅に制約をはる
- self.contentView.leadingAnchor.constraintEqualToAnchor(self.leadingAnchor).active = true
- self.contentView.trailingAnchor.constraintEqualToAnchor(self.trailingAnchor).active = true
- self.contentView.topAnchor.constraintEqualToAnchor(self.topAnchor).active = true
- self.contentView.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = true
+ self.contentView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
+ self.contentView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
+ self.contentView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
+ self.contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
self.layoutIfNeeded()
}
AutoLayoutBookSampler/Ch4/XibAndStoryboardViewController.swift
@@ -17,8 +17,8 @@ class XibAndStoryboardViewController: UIViewController {
subView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(subView)
- subView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
- subView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
- subView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true
+ subView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
+ subView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
+ subView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
5章の修正
/AutoLayoutBookSampler/Ch5/LayoutGuideViewController.swift
@@ -22,19 +22,19 @@ class LayoutGuideViewController: UIViewController {
view.addLayoutGuide(space)
// レイアウトガイドの幅をボタンと揃える
- space.widthAnchor.constraintEqualToAnchor(saveButton.widthAnchor).active = true
+ space.widthAnchor.constraint(equalTo: saveButton.widthAnchor).isActive = true
// レイアウトガイドを中央揃え
- space.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
+ space.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// 各ボタンとレイアウトガイドの水平方向の制約生成
- saveButton.trailingAnchor.constraintEqualToAnchor(space.leadingAnchor).active = true
- cancelButton.leadingAnchor.constraintEqualToAnchor(space.trailingAnchor).active = true
+ saveButton.trailingAnchor.constraint(equalTo: space.leadingAnchor).isActive = true
+ cancelButton.leadingAnchor.constraint(equalTo: space.trailingAnchor).isActive = true
view.layoutIfNeeded()
}
- override func viewDidAppear(animated: Bool) {
+ override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
6章の修正
/AutoLayoutBookSampler/Ch6/TorutsumeViewController.swift
@@ -34,27 +34,27 @@ class TorutsumeViewController: UIViewController {
}
@IBAction func PressButtonButton(sender: AnyObject) {
- if button.hidden {
+ if button.isHidden {
buttonHeightConstraint.constant = 30
buttonTopConstraint.constant = 8
- button.hidden = false
+ button.isHidden = false
}
else { buttonHeightConstraint.constant = 0
buttonTopConstraint.constant = 0
- button.hidden = true
+ button.isHidden = true
}
}
@IBAction func PressSwichButton(sender: AnyObject) {
- if swichButton.hidden {
+ if swichButton.isHidden {
swichTopConstraint.constant = 8
swichHeightConstraint.constant = 31
- swichButton.hidden = false
+ swichButton.isHidden = false
}
else {
swichTopConstraint.constant = 0
swichHeightConstraint.constant = 0
- swichButton.hidden = true
+ swichButton.isHidden = true
}
}
}
7章の修正
/AutoLayoutBookSampler/Ch7/DeviceRotationViewController.swift
@@ -33,29 +33,29 @@ class DeviceRotationViewController: UIViewController {
// Dispose of any resources that can be recreated.
}
- override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
+ override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// 回転時のレイアウト変更を以下のメソッド内で定義することで、回転時のアニメーションと同期して動きます。
- super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
+ super.viewWillTransition(to: size, with: coordinator)
- coordinator.animateAlongsideTransition(
- {
+ _ = coordinator.animate(
+ alongsideTransition: {
context in
// 縦画面レイアウト
if size.width <= size.height {
// 横画面用制約を無効化
- NSLayoutConstraint.deactivateConstraints(self.landscapeConstraints ?? [])
+ NSLayoutConstraint.deactivate(self.landscapeConstraints ?? [])
// 縦画面用制約を有効化
- NSLayoutConstraint.activateConstraints(self.portraitConstraints ?? [])
+ NSLayoutConstraint.activate(self.portraitConstraints ?? [])
}
// 横画面レイアウト
else {
// 縦画面用制約を無効化
- NSLayoutConstraint.deactivateConstraints(self.portraitConstraints ?? [])
+ NSLayoutConstraint.deactivate(self.portraitConstraints ?? [])
// 横画面用制約を有効化
- NSLayoutConstraint.activateConstraints(self.landscapeConstraints ?? [])
+ NSLayoutConstraint.activate(self.landscapeConstraints ?? [])
}
}, completion: nil)
}
/AutoLayoutBookSampler/Ch7/OffscreenRenderingCellTableViewCell.swift
@@ -17,8 +17,7 @@ class OffscreenRenderingCellTableViewCell: UITableViewCell {
super.awakeFromNib()
// Initialization code
}
-
- override func setSelected(selected: Bool, animated: Bool) {
+ override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
/AutoLayoutBookSampler/Ch7/OffscreenRenderingCellViewController.swift
@@ -24,13 +24,13 @@ class OffscreenRenderingCellViewController: UIViewController, UITableViewDelegat
// MARK: UITableViewDataSource
- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCellWithIdentifier("OffscreenRenderingCell") as? OffscreenRenderingCellTableViewCell
- cell!.layoutWithData(people[indexPath.row])
+ internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "OffscreenRenderingCell") as? OffscreenRenderingCellTableViewCell
+ cell!.layoutWithData(data: people[indexPath.row])
return cell!
}
@@ -39,11 +39,11 @@ class OffscreenRenderingCellViewController: UIViewController, UITableViewDelegat
}
// MARK: UITableViewDelegate
- func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
+ internal func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// セル生成時の計算コストを減らすため一度だけインスタンス化
if cellForCalculatingHeight == nil {
- guard let reusableCell = tableView.dequeueReusableCellWithIdentifier("OffscreenRenderingCell") as? OffscreenRenderingCellTableViewCell else {
+ guard let reusableCell = tableView.dequeueReusableCell(withIdentifier: "OffscreenRenderingCell") as? OffscreenRenderingCellTableViewCell else {
fatalError("Your cellIdentifier is invalid")
}
cellForCalculatingHeight = reusableCell
@@ -56,10 +56,10 @@ class OffscreenRenderingCellViewController: UIViewController, UITableViewDelegat
// レイアウト用データを代入
- cell.layoutWithData(self.personForRow(indexPath.row))
+ cell.layoutWithData(data: self.personForRow(index: indexPath.row))
// レイアウトに必要なテーブルビューの幅を与える
- cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds))
+ cell.bounds = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: cell.bounds.height)
// セルの高さを計算する
return cell.calculateHeight()
@@ -75,9 +75,9 @@ extension UITableViewCell {
func calculateHeight() -> CGFloat {
self.layoutIfNeeded()
- let cellHeight = contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
+ let cellHeight = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
// セパレータの高さ1.0を足す
return cellHeight + 1.0
}
-}
\ No newline at end of file
+}
/AutoLayoutBookSampler/Ch7/People.swift
@@ -26,18 +26,17 @@ class People: NSObject {
class func generateCellData() -> [Person] {
var people = [Person]()
- var plistArray: NSArray?
- if let path = NSBundle.mainBundle().pathForResource("people", ofType: "plist") {
- plistArray = NSArray(contentsOfFile: path)
+ var plist: NSArray?
+ if let path = Bundle.main.path(forResource: "people", ofType: "plist") {
+ plist = NSArray(contentsOfFile: path)
}
for _ in 0..<numberOfData {
- let index = Int(arc4random_uniform(UInt32(plistArray!.count)))
- let personDic = plistArray![index]
-
- let name = personDic["name"] as? String
- let detail = personDic["detail"] as? String
+ let index = Int(arc4random_uniform(UInt32(plist!.count)))
+ let personDic = plist![index] as? Dictionary<String, String>
+ let name = personDic?["name"]
+ let detail = personDic?["detail"]
let person = Person(name: name!, detail: detail!)
people.append(person)
}
/AutoLayoutBookSampler/Ch7/SelfSizingCellViewController.swift
@@ -18,35 +18,35 @@ class SelfSizingCellViewController: UIViewController, UITableViewDelegate, UITab
// Set up auto resizing cell
self.tableView.estimatedRowHeight = 100.0
- tableView.rowHeight = UITableViewAutomaticDimension
+ tableView.rowHeight = UITableView.automaticDimension
people = People.generateCellData()
// Dynamic Typeのための通知受け取り
- NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(self.didChangePreferredContentSize(_:)), name: UIContentSizeCategoryDidChangeNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector:#selector(self.didChangePreferredContentSize), name: UIContentSizeCategory.didChangeNotification, object: nil)
}
deinit {
- NSNotificationCenter.defaultCenter().removeObserver(self)
+ NotificationCenter.default.removeObserver(self)
}
- func didChangePreferredContentSize(notification: NSNotification) {
+ @objc func didChangePreferredContentSize(notification: NSNotification) {
tableView.reloadData()
}
// MARK: UITableViewDataSource
- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// セルの取得
- guard let cell = tableView.dequeueReusableCellWithIdentifier("SelfSizingCellTableViewCell", forIndexPath: indexPath) as? SelfSizingCellTableViewCell else {
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: "SelfSizingCellTableViewCell", for: indexPath) as? SelfSizingCellTableViewCell else {
fatalError("Your cellIdentifier is invalid")
}
// データを渡しレイアウト実行
- cell.layoutWithData(self.personForRow(indexPath.row))
+ cell.layoutWithData(data: self.personForRow(index: indexPath.row))
return cell
}
- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
/AutoLayoutBookSampler/Ch7/keyboardAppearanceViewController.swift
@@ -13,46 +13,46 @@ class keyboardAppearanceViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
- NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardAppearanceViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
- NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardAppearanceViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardAppearanceViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardAppearanceViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
- func keyboardWillShow(notification: NSNotification) {
+ @objc func keyboardWillShow(_ notification: Notification) {
guard let info = notification.userInfo else {
fatalError("Unexpected notification")
}
// キーボードの高さを取得
- guard let keyboardHeight = info[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height else {
+ guard let keyboardHeight = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height else {
fatalError("No keyboard height found")
}
// キーボード表示アニメーションの時間を取得
- guard let animationDuration = info[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue else {
+ guard let animationDuration = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {
fatalError("No keyboard height found")
}
// 取得した情報を元にスクロールビューのレイアウトを変更する
buttomConstraint.constant = keyboardHeight
- UIView.animateWithDuration(animationDuration, animations: { () -> Void in
+ UIView.animate(withDuration: animationDuration, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
- func keyboardWillHide(notification: NSNotification) {
+ @objc func keyboardWillHide(_ notification: Notification) {
guard let info = notification.userInfo else {
fatalError("Unexpected notification")
}
// キーボード表示アニメーションの時間を取得
- guard let animationDuration = info[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue else {
+ guard let animationDuration = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {
fatalError("No keyboard height found")
}
// 取得した情報を元にスクロールビューのレイアウトを変更する
buttomConstraint.constant = 0
- UIView.animateWithDuration(animationDuration, animations: { () -> Void in
+ UIView.animate(withDuration: animationDuration, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
8章の修正
/AutoLayoutBookSampler/Ch8/AmbiguousLayoutViewController.swift
@@ -10,7 +10,7 @@ import UIKit
class AmbiguousLayoutViewController: UIViewController {
- override func viewDidAppear(animated: Bool) {
+ override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 曖昧なレイアウトを持つラベルを定義
@@ -20,12 +20,12 @@ class AmbiguousLayoutViewController: UIViewController {
view.addSubview(ambiguousLabel)
// 制約を垂直方向のみに与える
- ambiguousLabel.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true
+ ambiguousLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// 曖昧なレイアウトか確認
print(view.hasAmbiguity())
// 8.2.2 曖昧なレイアウトを視覚で確認する
- view.exerciseAmbiguityInLayoutRepeatedly(true)
+ view.exerciseAmbiguityInLayoutRepeatedly(recursive: true)
}
}
/AutoLayoutBookSampler/Ch8/AmbiguousLayoutWithPrivateMethodsViewController.swift
@@ -15,25 +15,25 @@ class AmbiguousLayoutWithPrivateMethodsViewController: UIViewController {
// ビューの階層構造を出力
@IBAction func recursiveDescriptionAction(sender: AnyObject) {
textView.text = view.recursiveDescription()
- textView.textColor = UIColor.whiteColor()
+ textView.textColor = UIColor.white
}
// ビューの階層構造とAuto Layoutの情報を出力
@IBAction func autolayoutTraceAction(sender: AnyObject) {
textView.text = view._autolayoutTrace()
- textView.textColor = UIColor.whiteColor()
+ textView.textColor = UIColor.white
}
// ビューコントローラの階層を確認する
@IBAction func printHierarchyAction(sender: AnyObject) {
textView.text = self._printHierarchy()
- textView.textColor = UIColor.whiteColor()
+ textView.textColor = UIColor.white
}
// 全てのインスタンスを確認する
@IBAction func ivarDescriptionAction(sender: AnyObject) {
textView.text = self._ivarDescription()
- textView.textColor = UIColor.whiteColor()
+ textView.textColor = UIColor.white
}
}
/AutoLayoutBookSampler/Ch8/ConflictedConstraintsViewController.swift
@@ -14,14 +14,14 @@ class ConflictedConstraintsViewController: UIViewController {
@IBAction func constraintsAffectingLayoutForAxisAction(sender: AnyObject) {
// 軸ごとに制約を分解する
- textView.text = textView.constraintsAffectingLayoutForAxis(.Horizontal).description
- textView.textColor = UIColor.whiteColor()
+ textView.text = textView.constraintsAffectingLayout(for: .horizontal).description
+ textView.textColor = UIColor.white
}
@IBAction func constraintsReferringViewAction(sender: AnyObject) {
// ビューごとに制約を分解する
- textView.text = view.constraintsReferringView(textView).description
- textView.textColor = UIColor.whiteColor()
+ textView.text = view.constraintsReferringView(view: textView).description
+ textView.textColor = UIColor.white
}
}
/AutoLayoutBookSampler/Ch8/DebugHelper.swift
@@ -14,7 +14,7 @@ extension UIView {
var hasAmbiguity = false
#if DEBUG
- if self.hasAmbiguousLayout() {
+ if self.hasAmbiguousLayout {
print("\(self.description) : AMBIGUOUS")
hasAmbiguity = true;
}
@@ -32,13 +32,13 @@ extension UIView {
func exerciseAmbiguityInLayoutRepeatedly(recursive: Bool) {
- if self.hasAmbiguousLayout() {
- NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(UIView.exerciseAmbiguityInLayout), userInfo: nil, repeats: true)
+ if self.hasAmbiguousLayout {
+ UIKit.Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIView.exerciseAmbiguityInLayout), userInfo: nil, repeats: true)
}
if recursive {
for view in subviews {
- view .exerciseAmbiguityInLayoutRepeatedly(recursive)
+ view .exerciseAmbiguityInLayoutRepeatedly(recursive: recursive)
}
}
}
@@ -57,7 +57,7 @@ extension UIView {
// 共通の祖先ビューを探す
var currentTarget: UIView? = target
while let candidate = currentTarget {
- if let _ = hierarchy.indexOf(candidate) {
+ if hierarchy.contains(candidate) {
return candidate
}
currentTarget = candidate.superview
このスクラップは2022/04/10にクローズされました