scrolling wip with perf problems
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
//TODO: Implement support for bonus chapters
|
||||
//TODO: Implement scrolling support
|
||||
//TODO: Implement Anilist support?
|
||||
//TODO: Evict the oldest image from cache
|
||||
//TODO: Properly avoid swallowing of input from UICollectionView used for scrolling
|
||||
//TODO: Fix UICollectionView sizeForItemAt method performance either by caching or lazy loading
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -12,6 +12,12 @@ enum PageTurn {
|
||||
case previous
|
||||
}
|
||||
|
||||
enum ReadProgress: Codable {
|
||||
case leftToRight(chapter: Int, page: Int)
|
||||
case rightToLeft(chapter: Int, page: Int)
|
||||
case scroll(CGPoint)
|
||||
}
|
||||
|
||||
enum PageTurnMode: Codable {
|
||||
case leftToRight
|
||||
case rightToLeft
|
||||
@@ -29,9 +35,7 @@ struct GlobalState: Codable {
|
||||
}
|
||||
|
||||
struct LocalState: Codable {
|
||||
var chapter: Int
|
||||
var page: Int
|
||||
var turnMode: PageTurnMode = .leftToRight
|
||||
var progress: ReadProgress
|
||||
var backgroundColor: String = "black"
|
||||
}
|
||||
|
||||
@@ -53,7 +57,7 @@ struct Metadata: Decodable {
|
||||
struct ChapterMetadata: Decodable {
|
||||
var chapter: Float
|
||||
var volume: Float
|
||||
var title: String
|
||||
var title: String?
|
||||
var pages: Int
|
||||
}
|
||||
|
||||
@@ -61,6 +65,11 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var homeView = UIView()
|
||||
var readerView = UIView()
|
||||
|
||||
@IBOutlet var scrollingCollectionView: UICollectionView!
|
||||
var scrollPos: CGPoint!
|
||||
var hasSetContentOffset = false
|
||||
var pageCount = 0
|
||||
|
||||
var imageView = UIImageView()
|
||||
var mode = PageTurnMode.leftToRight
|
||||
var metadata: Metadata!
|
||||
@@ -71,6 +80,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var leftTap: UITapGestureRecognizer!
|
||||
var rightTap: UITapGestureRecognizer!
|
||||
var topTap: UITapGestureRecognizer!
|
||||
let leftView = UIView()
|
||||
let rightView = UIView()
|
||||
let topView = UIView()
|
||||
|
||||
let topBarView = UIView()
|
||||
let bottomBarView = UIView()
|
||||
@@ -90,7 +102,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
let documentsURL = getDocumentsURL().unsafelyUnwrapped
|
||||
|
||||
var comics: [Comic] = []
|
||||
var collectionView: UICollectionView!
|
||||
@IBOutlet var comicCollectionView: UICollectionView!
|
||||
|
||||
let imageLoader = ImageLoader.init()
|
||||
|
||||
@@ -133,6 +145,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
])
|
||||
loadComics()
|
||||
setupImageView()
|
||||
setupScrollingCollectionView()
|
||||
setupGestures()
|
||||
setupBar()
|
||||
setupHomeView()
|
||||
@@ -147,13 +160,14 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
layout.minimumInteritemSpacing = spacing
|
||||
layout.minimumLineSpacing = spacing
|
||||
|
||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
collectionView.backgroundColor = .white
|
||||
collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")
|
||||
homeView.addSubview(collectionView)
|
||||
comicCollectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
comicCollectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
comicCollectionView.dataSource = self
|
||||
comicCollectionView.delegate = self
|
||||
comicCollectionView.backgroundColor = .white
|
||||
comicCollectionView.register(
|
||||
ComicImageCell.self, forCellWithReuseIdentifier: "ComicImageCell")
|
||||
homeView.addSubview(comicCollectionView)
|
||||
}
|
||||
|
||||
func loadComics() {
|
||||
@@ -230,13 +244,20 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
func saveLocalState() {
|
||||
let color = readerView.backgroundColor ?? .black
|
||||
let progress: ReadProgress =
|
||||
switch self.mode {
|
||||
case .leftToRight:
|
||||
ReadProgress.leftToRight(chapter: self.currentChapter, page: self.currentPage)
|
||||
case .rightToLeft:
|
||||
ReadProgress.leftToRight(chapter: self.currentChapter, page: self.currentPage)
|
||||
case .scroll: ReadProgress.scroll(scrollingCollectionView.contentOffset)
|
||||
}
|
||||
localStateQueue.async {
|
||||
do {
|
||||
try JSONEncoder().encode(
|
||||
LocalState(
|
||||
chapter: self.currentChapter, page: self.currentPage, turnMode: self.mode,
|
||||
backgroundColor: self.convertColorToString(
|
||||
color: color))
|
||||
progress: progress, backgroundColor: self.convertColorToString(color: color)
|
||||
)
|
||||
).write(
|
||||
to: self.currentPath.appendingPathComponent("state.json"))
|
||||
} catch {
|
||||
@@ -252,9 +273,21 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
contentsOfFile: currentPath.appendingPathComponent("state.json").path
|
||||
).utf8)
|
||||
let local = try JSONDecoder().decode(LocalState.self, from: json)
|
||||
currentPage = local.page
|
||||
currentChapter = local.chapter
|
||||
mode = local.turnMode
|
||||
switch local.progress {
|
||||
case .leftToRight(let chapter, let page):
|
||||
self.currentChapter = chapter
|
||||
self.currentPage = page
|
||||
self.mode = .leftToRight
|
||||
case .rightToLeft(let chapter, let page):
|
||||
self.currentChapter = chapter
|
||||
self.currentPage = page
|
||||
self.mode = .rightToLeft
|
||||
case .scroll(let point):
|
||||
if self.scrollPos == nil {
|
||||
self.scrollPos = point
|
||||
}
|
||||
self.mode = .scroll
|
||||
}
|
||||
readerView.backgroundColor = convertStringToColor(str: local.backgroundColor)
|
||||
} catch {
|
||||
print("failed to load local state")
|
||||
@@ -273,6 +306,36 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
setupTapZones()
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if scrollingCollectionView.isHidden { return }
|
||||
let centerPoint = CGPoint(
|
||||
x: scrollingCollectionView.bounds.midX + scrollingCollectionView.contentOffset.x,
|
||||
y: scrollingCollectionView.bounds.midY + scrollingCollectionView.contentOffset.y)
|
||||
|
||||
if let indexPath = scrollingCollectionView.indexPathForItem(at: centerPoint) {
|
||||
var index = 0
|
||||
var (chapter, page) = (1, 1)
|
||||
while index < indexPath.item {
|
||||
(chapter, page) = getChapterAndPageFromTurn(
|
||||
chapter: chapter, page: page, turn: .next)
|
||||
index += 1
|
||||
}
|
||||
currentChapter = chapter
|
||||
currentPage = page
|
||||
}
|
||||
if scrollingCollectionView.isHidden == false {
|
||||
saveLocalState()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
if scrollingCollectionView.isHidden == false && mode == .scroll && !hasSetContentOffset {
|
||||
scrollingCollectionView.setContentOffset(scrollPos, animated: false)
|
||||
hasSetContentOffset = true
|
||||
}
|
||||
}
|
||||
|
||||
func readComic(name: String) {
|
||||
readerView.isHidden = false
|
||||
homeView.isHidden = true
|
||||
@@ -280,18 +343,50 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
if let path = getPathFromComicName(name: name) {
|
||||
currentPath = path
|
||||
metadata = getMetadata(path: path)!
|
||||
pageCount = metadata.chapters.map { $0.pages }.reduce(0, +)
|
||||
globalState.comicName = metadata.title
|
||||
saveGlobalState()
|
||||
loadLocalState()
|
||||
if mode != .scroll {
|
||||
scrollingCollectionView.isHidden = true
|
||||
leftView.isHidden = false
|
||||
rightView.isHidden = false
|
||||
setImages(path: path, metadata: metadata)
|
||||
} else {
|
||||
leftView.isHidden = true
|
||||
rightView.isHidden = true
|
||||
scrollingCollectionView.isHidden = false
|
||||
scrollingCollectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupScrollingCollectionView() {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumInteritemSpacing = 0
|
||||
layout.minimumLineSpacing = 0
|
||||
scrollingCollectionView = UICollectionView(
|
||||
frame: view.bounds, collectionViewLayout: layout)
|
||||
scrollingCollectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
scrollingCollectionView.isUserInteractionEnabled = true
|
||||
scrollingCollectionView.dataSource = self
|
||||
scrollingCollectionView.delegate = self
|
||||
scrollingCollectionView.backgroundColor = .white
|
||||
scrollingCollectionView.isHidden = true
|
||||
scrollingCollectionView.register(
|
||||
ScrollingImageCell.self, forCellWithReuseIdentifier: "ScrollingImageCell")
|
||||
readerView.addSubview(scrollingCollectionView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
scrollingCollectionView.topAnchor.constraint(equalTo: readerView.topAnchor),
|
||||
scrollingCollectionView.leadingAnchor.constraint(equalTo: readerView.leadingAnchor),
|
||||
scrollingCollectionView.trailingAnchor.constraint(equalTo: readerView.trailingAnchor),
|
||||
scrollingCollectionView.heightAnchor.constraint(equalTo: readerView.heightAnchor),
|
||||
])
|
||||
|
||||
}
|
||||
|
||||
func setupTapZones() {
|
||||
let leftView = UIView()
|
||||
let rightView = UIView()
|
||||
let topView = UIView()
|
||||
|
||||
leftView.translatesAutoresizingMaskIntoConstraints = false
|
||||
rightView.translatesAutoresizingMaskIntoConstraints = false
|
||||
topView.translatesAutoresizingMaskIntoConstraints = false
|
||||
@@ -370,6 +465,10 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
info.textColor = .white
|
||||
bottomBarView.addSubview(info)
|
||||
NSLayoutConstraint.activate([
|
||||
info.topAnchor.constraint(equalTo: bottomBarView.topAnchor),
|
||||
info.bottomAnchor.constraint(equalTo: bottomBarView.bottomAnchor),
|
||||
info.leadingAnchor.constraint(equalTo: bottomBarView.leadingAnchor),
|
||||
info.trailingAnchor.constraint(equalTo: bottomBarView.trailingAnchor),
|
||||
info.centerXAnchor.constraint(equalTo: bottomBarView.centerXAnchor),
|
||||
info.centerYAnchor.constraint(equalTo: bottomBarView.centerYAnchor),
|
||||
])
|
||||
@@ -543,10 +642,17 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
switch title.lowercased() {
|
||||
case "left to right": mode = .leftToRight
|
||||
case "right to left": mode = .rightToLeft
|
||||
case "scroll": mode = .scroll
|
||||
case "scroll":
|
||||
if mode != .scroll {
|
||||
scrollingCollectionView.reloadData()
|
||||
}
|
||||
mode = .scroll
|
||||
default: break
|
||||
}
|
||||
}
|
||||
scrollingCollectionView.isHidden = mode != .scroll
|
||||
leftView.isHidden = mode == .scroll
|
||||
rightView.isHidden = mode == .scroll
|
||||
togglePageTurnDropdown()
|
||||
saveLocalState()
|
||||
}
|
||||
@@ -574,17 +680,24 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
backgroundColorDropdownView.isHidden.toggle()
|
||||
}
|
||||
|
||||
// func gestureRecognizer(
|
||||
// _ gestureRecognizer: UIGestureRecognizer,
|
||||
// shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer
|
||||
// ) -> Bool {
|
||||
// if gestureRecognizer == leftTap || gestureRecognizer == rightTap,
|
||||
// otherGestureRecognizer == topTap
|
||||
// {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
|
||||
func gestureRecognizer(
|
||||
_ gestureRecognizer: UIGestureRecognizer,
|
||||
shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer
|
||||
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer
|
||||
) -> Bool {
|
||||
if gestureRecognizer == leftTap || gestureRecognizer == rightTap,
|
||||
otherGestureRecognizer == topTap
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func toggleBar() {
|
||||
topBarView.isHidden.toggle()
|
||||
@@ -596,6 +709,20 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
if scrollingCollectionView.isHidden { return }
|
||||
updateInfo()
|
||||
saveLocalState()
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
if scrollingCollectionView.isHidden { return }
|
||||
if !decelerate {
|
||||
updateInfo()
|
||||
}
|
||||
saveLocalState()
|
||||
}
|
||||
|
||||
func hideBar() {
|
||||
topBarView.isHidden = true
|
||||
bottomBarView.isHidden = true
|
||||
@@ -690,14 +817,26 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func updateInfo() {
|
||||
info.text = """
|
||||
\(metadata.title)
|
||||
\(metadata.chapters[currentChapter - 1].title)
|
||||
if metadata == nil { return }
|
||||
if currentChapter == nil || currentPage == nil { return }
|
||||
|
||||
var text = "\(metadata.title)\n"
|
||||
|
||||
if let chapterTitle = metadata.chapters[currentChapter - 1].title {
|
||||
text =
|
||||
text + "\(chapterTitle)"
|
||||
}
|
||||
text =
|
||||
text + """
|
||||
Volume \(Int(metadata.chapters[currentChapter - 1].volume)) of \(Int(metadata.last_volume))
|
||||
Chapter \(currentChapter!) of \(Int(metadata.last_chapter))
|
||||
Page \(currentPage!) of \(metadata.chapters[currentChapter - 1].pages)
|
||||
Image size: \(Int(imageView.image!.size.width))x\(Int(imageView.image!.size.height))
|
||||
"""
|
||||
if let image = imageView.image {
|
||||
text =
|
||||
text + "\nImage size: \(Int(image.size.width))x\(Int(image.size.height))"
|
||||
}
|
||||
info.text = text
|
||||
}
|
||||
|
||||
func getImagePath(chapter: Int, volume: Int, page: Int, path: URL) -> URL! {
|
||||
@@ -706,21 +845,6 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
if fileManager.fileExists(atPath: modernPath.path) {
|
||||
return modernPath
|
||||
}
|
||||
//TODO: Remove this
|
||||
let newPath = path.appendingPathComponent(String(format: "volume_%04d", volume))
|
||||
.appendingPathComponent(
|
||||
String(format: "chapter_%04d_image_%04d.png", chapter, page - 1))
|
||||
if fileManager.fileExists(atPath: newPath.path) {
|
||||
return newPath
|
||||
}
|
||||
let alternatePath = path.appendingPathComponent(String(format: "volume_%04d", volume))
|
||||
.appendingPathComponent(
|
||||
String(format: "chapter%03d_image_%03d.png", chapter, page - 1))
|
||||
if fileManager.fileExists(atPath: alternatePath.path) {
|
||||
return alternatePath
|
||||
}
|
||||
//
|
||||
print("Did not find image at path")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -822,12 +946,10 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
currentPage = Int(path_meta[3].components(separatedBy: ".")[0])
|
||||
if currentPage == nil {
|
||||
print("unable to set currentPage")
|
||||
assert(false)
|
||||
}
|
||||
} else {
|
||||
// TODO: Remove this
|
||||
assert(path_meta[2] == "image")
|
||||
currentPage = Int(path_meta[3].components(separatedBy: ".")[0])! + 1
|
||||
}
|
||||
saveLocalState()
|
||||
updateInfo()
|
||||
} catch {
|
||||
print("failed to set images")
|
||||
@@ -872,40 +994,139 @@ func getDocumentsURL() -> URL? {
|
||||
|
||||
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int)
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView, numberOfItemsInSection section: Int
|
||||
)
|
||||
-> Int
|
||||
{
|
||||
if collectionView == comicCollectionView {
|
||||
return comics.count
|
||||
} else {
|
||||
return pageCount
|
||||
}
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
|
||||
-> UICollectionViewCell
|
||||
{
|
||||
if collectionView == comicCollectionView {
|
||||
let cell =
|
||||
collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath)
|
||||
as! ImageCell
|
||||
collectionView.dequeueReusableCell(
|
||||
withReuseIdentifier: "ComicImageCell", for: indexPath)
|
||||
as! ComicImageCell
|
||||
cell.imageView.image = comics[indexPath.item].cover
|
||||
return cell
|
||||
} else if collectionView == scrollingCollectionView {
|
||||
let cell =
|
||||
collectionView.dequeueReusableCell(
|
||||
withReuseIdentifier: "ScrollingImageCell", for: indexPath)
|
||||
as! ScrollingImageCell
|
||||
if metadata == nil {
|
||||
return cell
|
||||
}
|
||||
var index = 0
|
||||
var (chapter, page) = (1, 1)
|
||||
while index < indexPath.item {
|
||||
(chapter, page) = getChapterAndPageFromTurn(
|
||||
chapter: chapter, page: page, turn: .next)
|
||||
index += 1
|
||||
}
|
||||
if let url = getImagePath(
|
||||
chapter: chapter,
|
||||
volume: Int(metadata.chapters[chapter - 1].volume),
|
||||
page: page, path: currentPath)
|
||||
{
|
||||
// cell.imageView.image = UIImage(contentsOfFile: url.path)
|
||||
imageLoader.loadImage(at: url) { image in cell.imageView.image = image }
|
||||
}
|
||||
return cell
|
||||
} else {
|
||||
assert(false)
|
||||
}
|
||||
|
||||
// Xcode profiling sucks:
|
||||
return
|
||||
collectionView.dequeueReusableCell(
|
||||
withReuseIdentifier: "ScrollingImageCell", for: indexPath)
|
||||
as! ScrollingImageCell
|
||||
}
|
||||
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
|
||||
_ collectionView: UICollectionView,
|
||||
layout collectionViewLayout: UICollectionViewLayout,
|
||||
sizeForItemAt indexPath: IndexPath
|
||||
) -> CGSize {
|
||||
if collectionView == comicCollectionView {
|
||||
let spacing: CGFloat = 8
|
||||
let itemsPerRow: CGFloat = 3
|
||||
let totalSpacing = (itemsPerRow - 1) * spacing
|
||||
let width = (collectionView.bounds.width - totalSpacing) / itemsPerRow
|
||||
return CGSize(width: width, height: width)
|
||||
} else if collectionView == scrollingCollectionView {
|
||||
if metadata == nil {
|
||||
return CGSize()
|
||||
}
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
var index = 0
|
||||
var (chapter, page) = (1, 1)
|
||||
while index < indexPath.item {
|
||||
(chapter, page) = getChapterAndPageFromTurn(
|
||||
chapter: chapter, page: page, turn: .next)
|
||||
index += 1
|
||||
}
|
||||
if let imagePath = getImagePath(
|
||||
chapter: chapter,
|
||||
volume: Int(metadata.chapters[chapter - 1].volume),
|
||||
page: page, path: currentPath),
|
||||
let imageSource = CGImageSourceCreateWithURL(imagePath as CFURL, nil),
|
||||
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)
|
||||
as? [CFString: Any],
|
||||
let height = imageProperties[kCGImagePropertyPixelHeight] as? CGFloat
|
||||
{
|
||||
return CGSize(width: readerView.bounds.width, height: height)
|
||||
}
|
||||
return CGSize(width: readerView.bounds.width, height: readerView.bounds.height)
|
||||
} else {
|
||||
assert(false)
|
||||
}
|
||||
// Xcode profiling sucks:
|
||||
return CGSize()
|
||||
}
|
||||
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath
|
||||
) {
|
||||
if collectionView == comicCollectionView {
|
||||
let selectedComic = comics[indexPath.item]
|
||||
|
||||
readComic(name: selectedComic.metadata.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ImageCell: UICollectionViewCell {
|
||||
class ScrollingImageCell: UICollectionViewCell {
|
||||
let imageView = UIImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
imageView.clipsToBounds = true
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(imageView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
class ComicImageCell: UICollectionViewCell {
|
||||
let imageView = UIImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
|
2
run.sh
2
run.sh
@@ -18,7 +18,7 @@ xcodebuild -scheme "$SCHEME" -configuration "$BUILD_TYPE" -derivedDataPath "$DER
|
||||
|
||||
APP_PATH="$DERIVED_DATA/Build/Products/Debug-iphonesimulator/$APP_NAME.app"
|
||||
xcrun simctl install booted "$APP_PATH"
|
||||
xcrun simctl spawn booted log stream --predicate 'process == "ImageViewer"' --style syslog &
|
||||
# xcrun simctl spawn booted log stream --predicate 'process == "ImageViewer"' --style syslog &
|
||||
xcrun simctl launch booted "$COMPANY.$APP_NAME"
|
||||
|
||||
sudo sed -i '' '/developerservices2\.apple\.com/d' /etc/hosts
|
||||
|
Reference in New Issue
Block a user