13 Aug 2018
|
TIL
2018.08.13
- segue๋ก nextVC๋์ฐ๊ธฐ์์ nextVC์ didSet์์ ์๋ฌ๊ฐ ๋์ ์ ๋ฆฌ
- ์๋์ฝ๋์์ ๋ณด๋ฉด SearchViewController์ prepare()๋ฉ์๋์์ ์คํ ๋ฆฌ๋ณด๋ segue์ ๋ฐ๋ผ์ ๋์
- segue๊ฐ ์คํ๋๋ฉด์ nextVC์ awakeFromNib() ์คํ.
- ์ด๋ nextVC์ self๋ ์ธ์คํด์คํ๋ ์ํ
- ์์๋ชจ๋์์
nextVC.branchData
์ ๋ฐ์ดํฐ ๊ฐ์ ๋๊ฒจ์ฃผ๋ฉด์ didSet์คํ์ด๋๋๋ฐ
- ์ด๋๊น์ง๋ IBOutlet์ ํ๋กํผํฐ๋ nil์ํ
- nextVC๊ฐ ์ธ์คํด์คํ๋ ์ํ์ฌ๋ ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์คํ ๋ฆฌ๋ณด๋๋ก ์ฐ๊ฒฐ๋ IBOutlet๋ค์ ์ฐธ์กฐ๊ด๊ณ๊ฐ ๋ถ๋ช
ํํ ์์ ์ด ์๋ค. ์ด๋๊ฐ ๋ฐ๋ก ๊ทธ ์์ ์ธ๋ฏํ๋ค.
- viewDidLoad()๊ฐ ์คํ๋๋ ์์ ์๋ nil์ด์๋ IBOutletํ๋กํผํฐ๋ค์ด ๋ก๋๊ฐ ์๋ฃ๋ ์์
- IBOutlet์ ์ธํ
ํ๋ ๋์์ viewDidLoad์์ ํ๋ฉด ๋์ํ๋ค.
// SearchViewController.swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "showDetail" else { return }
guard let nextVC = segue.destination as? DetailViewController else { return }
if let indexPath = tableView.indexPathForSelectedRow {
if isFiltering() {
nextVC.branchData = filtered!.branches[indexPath.row]
} else {
nextVC.branchData = list!.branches[indexPath.row]
}
}
}
}
// DetailViewController.swift
var branchData: Branch? {
didSet {
print("didSet")
}
}
override func awakeFromNib() {
super.awakeFromNib()
print(#function)
}
override func viewDidLoad() {
super.viewDidLoad()
setNavigationItem()
setTitle()
setAddress()
setHolidays()
setPhoneNumber()
}
2018.08.14
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication setNetworkActivityIndicatorVisible:]
2018.08.15
- ๋ทฐ ์คํ ๋ ์ด์์ ์ก๊ธฐ
- ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ชจ๋ธ ๊ตฌํ
- JSONํ์ผ์ด ๋ณ๊ฒฝ๋์ด๋ ๊ทธ๋๋ก ์ฆ๊ฒจ์ฐพ๊ธฐ๊ฐ ์ ์ง๋๊ณ ์
๋ฐ์ดํธ๋๋์ง ํ์ธ
2018.08.16
- AppDelegate์ ์ฝ๋ฐฑํจ์์์ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ / ๊ฐ์ ธ์ฌ๋์ ์๋ฌธ์
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// loadedData๊ฐ ์๋๊ฒฝ์ฐ favoriteList๋ฅผ ์ ์ฅํด์ฃผ์ง ์๊ณ ๊ทธ๋ฅ ๋์ด๊ฐ๋ฉด ํ์ ๋ชจ๋๋ค์์ ์ ๊ทผํ๋ FavoriteList.shared()๋ก ๋ฐ๋ ์ธ์คํด์ค๋ ๋ชจ๋ ๊ทธ๋ฅ Set<Int>()๋ก init์ด ๋๋๊น ์๊ด์์
guard let loadedData = DataStorage<FavoriteList>.load() else { return true }
FavoriteList.loadSavedData(loadedData) // Favorite๋ฆฌ์คํธ๋ฅผ ์ ์ฅํ๋ ์ธ์คํด์ค๋ก ๋์ฒดํด์ค
return true
}
// ์ฒซ ์์
application(_:didFinishLaunchingWithOptions:)
applicationDidBecomeActive
// ํ๋ฒํผ
applicationWillResignActive
applicationDidEnterBackground
// ์คํ(๋ฐฑ๊ทธ๋ผ์ด๋์๋ค๊ฐ ๊ทธ๋๋ก ๋ค์๋ฐ๋)
applicationWillEnterForeground
applicationDidBecomeActive
ํ๋ฒํผ ๋๋ฒ ๋๋ฌ์ ์๋ก ์ค์์ดํํ์ฌ ๋๋ ํธ์ถ์์ ํ
์คํธ
applicationWillResignActive
applicationDidEnterBackground
applicationWillTerminate
ํ
์คํธ์, ๋ฐฑ๊ทธ๋ผ์ด๋ ์๋๋ก ๊ฐ๋ ํญ์ ํธ์ถ๋๋ ํจ์
applicationWillResignActive
applicationDidEnterBackground // ์ค๋ซ๋์ active์ํ๊ฐ์๋๋
- ์๋น / ์ง์ง state๋ก ๋ค์ด๊ฐ๋๊ฑฐ ๊ผญ ๋๊ฐ์ฉ ํธ์ถ๋๋๋ฐ ์ด๋ป๊ฒ ๊ตฌ๋ถํ๊ณ ํจ์๋ฅผ ๊ตฌํํด์ผํ ๊น?
- ๋ชจ๋ ๊ตฌํํ๋๊ฒ ์ ์ผ ์ข์ง๋ง, ๋๊ฐ์ ๋์์ ๋ฐ๋ณตํ๊ฒ ํ๊ธฐ ๋ณด๋ค๋ ํด๋น ์ฝ๋ฐฑ๋ค์ด ๋ถ๋ฆฌ๋ ์๊ฐ์ฐจ๋์ ๋ด๊ฐ ์ ์ฅํ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ์ด ๋๋์ง flag๋ฅผ ๋๊ณ flag์ ๋ฐ๋ผ์ ๋์ํ๊ฒ ํ๋๊ฒ ์ข ๋ ๋์ ๋ฐฉ๋ฒ
- ์ฑ๋ธ๋ฆฌ๊ฒ์ดํธ ์ฝ๋ฐฑํจ์ ์ค resignActive๋ applicationWillTerminate๊ฐ์ ํจ์์์ ๋น๋๊ธฐ์์
์ ํ๋ฉด ํด๋น ์์
์ด ๋๋ ๋๊น์ง๋ ์ ์ง๋๋ค๊ณ ํ๋ค. ๋ณดํต์ 1๋ถ๋ด์ธ๋ก ์๋ ค์ ธ์์ง๋ง ์๊ฐ์ด ๋ ํ์ํ๋ค๋ฉด await์ฒ๋ฆฌ๋ฅผ ํด์ผ ํ ๊ฒ
2018.08.17
- ํ
์ด๋ธ๋ทฐ ์
์ ์๋ ๋ณ ์์ด์ฝ์ ๋ฒํผ์ผ๋ก ๋ฐ๊พธ๊ณ state๋ณ๊ฒฝ๋ ๋๋ง๋ค๋ก ํ์๋ณ - ๋
ธ๋์ ๋ณ๋ก ๋ฐ๊พธ๋๊น async๋ก ์์
ํ ํ์๊ฐ ์์ด์ง
- ํ
์ด๋ธ๋ทฐ ์
์ ๋ฐ์ดํฐ๋ฅผ detailํ๋ฉด์์ ๋ฐ๊พธ๊ณ ํ
์ด๋ธ๋ทฐ๋ก ํ๋ฉด์ด ๋์ด๊ฐ๋ ํด๋น ์
์ ์
๋ฐ์ดํธ๋์ง ์๊ณ ํด๋น ์
์ด ํ๋ฉด์์ ์ฌ๋ผ์ก๋ค๊ฐ ๋ํ๋๊ฑฐ๋ search๋์์ ์คํํด์ ํ
์ด๋ธ๋ทฐ๊ฐ reload๋ ๋๋ง ์
์ด ์
๋ฐ์ดํธ๋จ
- ์
์์ reuse๋ ๋ ๋ฒํผ ์ํ๋ฅผ updateํ ์ ์์๊น ๊ณ ๋ฏผํ๋๋ฐ,
- ์ด๋ฐ ๊ฒฝ์ฐ๋ ํ
์ด๋ธ๋ทฐ์ปจํธ๋กค๋ฌ์์ reload๋ฅผ ๋ฐ๋์ ํด์ค์ผํจ!
- xib๋ก ์ฌ์ด๋๋ฐ ์ฐ๊ฒฐํจ!!!!!!!!!!!!
- ์ฝ๋ ์
๋ทฐ๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ค๊ฐ ๊ทธ๋๋ก reuseํ๋ฉด ์๋ ๊ฑฐ๊ฐ์์.
- ๊ทธ๋ฆฌ๊ณ ์ฌ๋ผ์ด๋ ๋ฉ๋ด์ ๋ค์ด๊ฐ๋ ๋ฉ๋ด ์๊ฐ ๊ทธ๋ฆฌ ๋ง์ง ์์์
- ๋ฒํผ๊ณผ ์คํ๋ทฐ๋ก ๊ตฌํํ๋ฉด ์คํ๋ ค๋ ๋ด๊ฐ ์ํ๋ ์ฝ๋์ ๋ทฐ๋ฅผ ๋ง๋ค ์ ์์๊ฑฐ๊ฐ์์ ๊ตฌํํ๊ณ , ์ผ๋ฐ์ ์ธ ๋ทฐ ์ปจํธ๋กค๋ฌ ์์ ๋์ฐ๋ ๋ทฐ๊ฐ ์๋๋ผ ์ฌ์ด์ฆ๊ฐ ๋ค๋ฅด๊ธฐ๋๋ฌธ์ xib๋ก ํ๋ค.
- ์ปค์คํ
๋ธ๋ฆฌ๊ฒ์ดํธ ๋ง๋ฆ: MainViewController
- ์ฌ๋ผ์ด๋ ๋ฉ๋ด๋ฅผ ๋ซ๋ ๋์์ ํ๋ ๋ฉ์๋๋ ์ด๋์ ๊ตฌํํด์ผํ ๊น?
- (์ฌ๋ผ์ด๋ ๋ฉ๋ด๋ฅผ ๋ซ๋ ๋์์ ์ํ ์ต์ ๋ฒ๋ ์ด๋ ๊ตฌํ๋์ด์ผํ ๊น)
- SlideMenu์์ ๋ซ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด noti POST
- SlideLauncher์์ ๋ฐ์์ dismiss๋ฅผ ๋ฐ๋ก ํด๋ฒ๋ ค์ผํ๋
- delegate์ธ ๋ทฐ์ปจํธ๋กค๋ฌ์์ ๋ฐ์์ dismiss๋ฅผ ํด์ค์ผํ๋..?
2018.08.18
- ์ด๋ฏธ์ง์ ํ
์คํธ ํจ๊ป์๋ ๋ฒํผ ๋ง๋ค๊ธฐ
- ์ฌ์ด๋๋ฐ๋ ๊ฒน์น๋ statusBar ํ๋ฉด์ฒ๋ฆฌ
- ๊ฒฐ๊ตญ ๋ค๋น๊ฒ์ด์
์ embedํ๊ธฐ๋กโฆ.
08 Aug 2018
|
Swift
closure
ํด๋ก์ ์ ๊ฐ ํ๋ Capture
- ํด๋ก์ ๋ ์์ ์ด ์ ์๋ ์์น์ ์ฃผ๋ณ ๋ฌธ๋งฅ์ ํตํด ์์๋ ๋ณ์๋ฅผ ์บก์ณํ ์ ์๋ค.
- ์ด๋ฅผ ํตํด ํด๋ก์ ๋ ์ฃผ๋ณ์ ์ ์ํ ์์๋ ๋ณ์๊ฐ ๋์ด์ ์กด์ฌํ์ง์๋ํ๋ ์์ ๋ด๋ถ์์ ๊ทธ ๊ฐ์ ์ฐธ์กฐํ๊ฑฐ๋ ์์ ํ ์ ์์
- ์ด๋ ํด๋ก์ ๊ฐ ๋น๋๊ธฐ ์์
์ ๋ง์ด ์ฌ์ฉ๋๊ธฐ๋๋ฌธ
- ํด๋ก์ ๋ฅผ ํตํด ๋น๋๊ธฐ ์ฝ๋ฐฑ์ ์ฌ์ฉํ๋๊ฒฝ์ฐ ํ์ฌ ์ํ๋ฅผ ๋ฏธ๋ฆฌ ํ๋ํด๋์ง์์ผ๋ฉด ์ค์ ๋ก ํด๋ก์ ์ ๊ธฐ๋ฅ์ ์คํํ๋ ์๊ฐ์๋ ์ฃผ๋ณ์ ์์๋ ๋ณ์๊ฐ ์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ์ ์กด์ฌํ์ง ์์ ์ ์๊ธฐ๋๋ฌธ
Capture์ ๋ฌธ์
- ํด๋ก์ ๋ด๋ถ์์ ์ฐธ์กฐ๋ฅผ ํ๋ํ ๊ฐ์(ํด๋ก์ ๊ฐ ์บก์ณํ ๊ฐ) ํด๋ก์ ๋ด๋ถ์์ ๊ณ์ ์ด์์๋ค. (์ค์ฒฉํจ์ ๋ด๋ถ์ ์ง์ญ๋ณ์์ธ ๊ฒฝ์ฐ์๋ ํด๋ก์ ๊ฐ ์บก์ณํ๋ค๋ฉด ํด๋ก์ ๋ด๋ถ์์ ๊ณ์ ์์ด์ง์ง ์๊ณ ์์)
- ๋ฐ๋ผ์ ์บก์ณ๋ ๊ฐ์ ์ธ์ ํธ์ถ์ด ๋๋๋ผ๋ ํด๋ก์ ๊ฐ๊ฐ ์์ ๋ง์ ์ฐธ์กฐ๋ฅผ ๋ฏธ๋ฆฌ ํ๋ํ๊ธฐ๋๋ฌธ์ ๊ณ์ํด์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ด๋ ํด๋ก์ ์ ์ธ์คํด์ค ์ฌ์ด์ ๊ฐํ ์ฐธ์กฐ ์ํ ๋ฌธ์ ๊ฐ ๋ฐ์๋ ์ ์๋ค.
ํด๋ก์ ๋ ์ฐธ์กฐํ์
let increment: (()->Int) = makeIncrement(for:2)
- ์์๊ฐ์ด ํจ์์ ํด๋ก์ ๋ฅผ ๋ณ์์ ํ ๋น ํ๋ ๊ฒ์ ์์๋ ๋ณ์์ ์ฐธ์กฐ๋ฅผ ์ค์ ํ๋๊ฒ์
- ๋ง์ฝ ํด๋ก์ ์ ์ฐธ์กฐ๋ฅผ ๋ค๋ฅธ์์์ ํ ๋นํด์ค๋ค๋ฉด ์ด๋ ๋ ์์๊ฐ ๋ชจ๋ ๊ฐ์ ํด๋ก์ ๋ฅผ ๊ฐ๋ฆฌํจ๋ค๋๋ป์
ํ์ถํด๋ก์ @escaping
- ํจ์์ ์ธ์๋ก ์ ๋ฌ๋ ํด๋ก์ ๊ฐ ํจ์ ์ข
๋ฃ ํ์ ํธ์ถ๋ ๋ ํด๋ก์ ๊ฐ ํจ์๋ฅผ ํ์ถ(escape)ํ๋ค๊ณ ํํํจ
@escaping
ํค์๋ ์ฌ์ฉ
- ๋น๋๊ธฐ์์
์ผ๋ก ํจ์๊ฐ ์ข
๋ฃ๋๊ณ ๋ ํ ์์
์ด ๋๋๊ณ ํธ์ถํ ํ์๊ฐ ์๋ ํด๋ก์ ๋ฅผ ํ์ถํด๋ก์ ๋ก ์ฌ์ฉํจ์ผ๋ก์จ ํจ์ ์คํ์ ์์๋ฅผ ๋ณด์ฅํด์ค ์ ์๋ค.
- ํ์ถํด๋ก์ ์์ด ๋ช
ํํ๋ฐ
@escaping
ํค์๋๋ฅผ ๋ช
์ํ์ง ์์ผ๋ฉด ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํจ
- ๋ํ, ํ์ถํด๋ก์ ์์
self
ํค์๋ ํ์๋ ํ์์
```swift
typealias VoidvoidClosure = () -> Void
let firstClosure: VoidvoidClosure = {
print(โClosure Aโ)
}
let secondClosure: VoidvoidClosure = {
print(โClosure Bโ)
}
func returnOneClosure(first: @escaping VoidvoidClosure, second: @escaping VoidvoidClosure, shouldReturnFirstClosure: Bool) -> VoidvoidClosure {
// ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ ํด๋ก์ ๋ฅผ ๋ค์ ๋ฆฌํดํ๊ธฐ๋๋ฌธ์ ํจ์ ๋ฐ์ผ๋ก ํ์ถํ๋ ํ์ถ ํด๋ก์ ์ฌ์ผํจ
return shouldReturnFirstClosure ? first : second
}
let returnedClosure = returnOneClosure(first: firstClosure, second: secondClosure, shouldReturnFirstClosure: true)
returnedClosure() // returnOneClosureํจ์์ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ firstClosure๊ฐ ๋ฆฌํด๋์ด ์คํ. Closure A ์ถ๋ ฅ
var closures: [VoidvoidClosure] = []
// ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ฐ์ ํด๋ก์ ๊ฐ ํจ์ ์ธ๋ถ์ ๋ณ์์ ์ ์ฅ๋๋ฏ๋ก ํ์ถํด๋ก์
func appendClosure(closure: @escaping VoidvoidClosure) {
closures.append(closure)
}
## withoutActuallyEscaping
> [๊ณต์๋ฌธ์
](https://developer.apple.com/documentation/swift/2827967-withoutactuallyescaping)
- ์ค์ ๋ก๋ ํ์ถํ์ง ์๋๋ฐ ๋ค๋ฅธ ํจ์์์ ํ์ถ ํด๋ก์ ๋ฅผ ์๊ตฌํ๋ ์ํฉ์ ํด๋น
```swift
// withoutActuallyEscaping
func hasElements(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
return (array.lazy.filter{ predicate($0) }.isEmpty == false)
} //Error: Closure use of non-escaping parameter 'predicate' may allow it to escape
func hasElements(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
return withoutActuallyEscaping(predicate, do: { escapePredicate in
return (array.lazy.filter{ escapePredicate($0) }.isEmpty == false)
})
}
- withoutActuallyEscaping์ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ํ์ถํด๋ก์ ์ธ ์ฒ ํด์ผํ๋ ๋นํ์ถํด๋ก์ ์ ๋ฌ
withoutActuallyEscaping(_:do:)
์์ do
ํ๋ผ๋ฏธํฐ๋ ์ด ๋นํ์ถํด๋ก์ ๋ฅผ ๋ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ๋ฐ์ ์ค์ ๋ก ์์
์ ์คํํ ํ์ถํด๋ก์ ๋ฅผ ์ ๋ฌํจ
05 Aug 2018
|
TIL
2018.08.05
์ฃผ๋ง
2018-08-02 00:27:16.479396+0900 StoreApp[20099:888781] Task <887E6A12-0A54-4B07-B1F6-6DF0ED0857EF>.<1> finished with error - code: -1001
2018-08-02 00:27:16.493938+0900 StoreApp[20099:888781] Task <D1A56284-7F25-4C01-93AE-90353BC268E2>.<2> finished with error - code: -1001
2018-08-02 00:27:33.895061+0900 StoreApp[20099:888781] Task <28FBBC7F-9930-4104-800C-978099688827>.<3> finished with error - code: -1001
2018-08-02 00:27:33.932263+0900 StoreApp[20099:890156] Task <887E6A12-0A54-4B07-B1F6-6DF0ED0857EF>.<1> HTTP load failed (error code: -999 [1:89])
Network error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x60400025de80 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://crong.codesquad.kr:8080/woowa/main, NSErrorFailingURLKey=http://crong.codesquad.kr:8080/woowa/main, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
2018-08-02 00:27:34.709532+0900 StoreApp[20099:890156] Task <D1A56284-7F25-4C01-93AE-90353BC268E2>.<2> HTTP load failed (error code: -999 [1:89])
2018-08-02 00:27:34.713188+0900 StoreApp[20099:890156] Task <28FBBC7F-9930-4104-800C-978099688827>.<3> HTTP load failed (error code: -999 [1:89])
DataTask error: response
2018-08-02 00:27:47.118190+0900 StoreApp[20099:888727] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.54.4/UITableView.m:2012
2018-08-02 00:27:47.128271+0900 StoreApp[20099:888727] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (8 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
(
0 CoreFoundation 0x000000010605b1e6 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x0000000102168031 objc_exception_throw + 48
2 CoreFoundation 0x0000000106060472 +[NSException raise:format:arguments:] + 98
3 Foundation 0x0000000101c0b652 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
4 UIKit 0x000000010323ad9b -[UITableView _endCellAnimationsWithContext:] + 19031
5 UIKit 0x0000000103254787 -[UITableView endUpdates] + 75
6 StoreApp 0x00000001017babff _T08StoreApp0A14ViewControllerC010resetTableC033_5C3AD717C85DC9604A7179854EE8731CLLySay10Foundation9IndexPathVG10indexPaths_tFyycfU_ + 1391
7 StoreApp 0x00000001017be031 _T08StoreApp0A14ViewControllerC010resetTableC033_5C3AD717C85DC9604A7179854EE8731CLLySay10Foundation9IndexPathVG10indexPaths_tFyycfU_TA + 17
8 StoreApp 0x00000001017bac5d _T0Ig_IyB_TR + 45
9 libdispatch.dylib 0x000000010787b7ec _dispatch_client_callout + 8
10 libdispatch.dylib 0x0000000107888642 _dispatch_sync_thread_bound_invoke + 386
11 libdispatch.dylib 0x000000010787b7ec _dispatch_client_callout + 8
12 libdispatch.dylib 0x00000001078868cf _dispatch_main_queue_callback_4CF + 628
13 CoreFoundation 0x000000010601dc99 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
14 CoreFoundation 0x0000000105fe1ea6 __CFRunLoopRun + 2342
15 CoreFoundation 0x0000000105fe130b CFRunLoopRunSpecific + 635
16 GraphicsServices 0x0000000109d8aa73 GSEventRunModal + 62
17 UIKit 0x0000000103119057 UIApplicationMain + 159
18 StoreApp 0x00000001017bedd7 main + 55
19 libdyld.dylib 0x00000001078f8955 start + 1
20 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
2018.08.06
- ์ด๊ฑฐ ์ง๋ฌธํ๊ธฐ
- ์ง๋ฌธ๊ฑฐ๋ฆฌ
- Create a session configuration
- Create a session (with delegate)
- Create Task object with URL
- Send request with closure
- Wait for response (background)
- Wait and receive for data
- Finish or Error by closure
session() - 1,2,3 task๋ง๋ค๊ณ sessionํจ์ ์ข
๋ฃ
task.resume() - 4,5??
viewDidLoad์ข
๋ฃ
sessionํจ์์ taskํด๋ก์ ์คํ- ๋ค๋ฅธ thread์์..-6,7?
(mainthread์์๋ viewdidLoadํจ์๊ฐ ์ข
๋ฃ๋์ผ๋ฏ๋ก ์๋ฌด ์ผ๋ ์ผ์ด๋์ง์๋์ค)
ํด๋ก์ ์ response๋ฐ๊ณ ViewController์ storeItems ๊ฐ์ฒด์ ๊ฐ์ด ํ ๋น๋๋ ๋ธ๋ญ์์ handler()์คํ
์ด ์ํ์์ viewdidLoad๋๋๋ฉด ๋น ํ
์ด๋ธ๋ทฐ๋ก ์ด๋ฏธ ๊ทธ๋ ค์ก๊ณ ๊ธฐ๋ค๋ฆฌ๋์ค์ธ๊ฑด๊ฐ?
2018.08.07
- ํ
์ด๋ธ๋ทฐ ๋ฐ์ดํฐ์ ๋ทฐ ๋ก๋์ค์ ์๋ฌ ์ฒ๋ฆฌ ์ง๋ฌธ
- ๋น๋๊ธฐ์ ๋๊ธฐ์๋ฐ๋ฅธ ์๋ฌ ์์ธ ๊ตฌ๋ถ
- ์คํ ์ด์ฑ Step8 PR๋ณด๋
- statusbar ์คํ์ผ ๋ณ๊ฒฝ appdelegate์์ํ๋ ๋ฐฉ๋ฒ
- ์์
์นดํ๋ก๊ทธ์ color์์
์ถ๊ฐํ์ฌ ์ฌ์ฉ. ํ๋ก์ ํธ ๋ด์์ ์์ฃผ ์ฐ๋ ์๊น์
UIColor(named: "์์
์ด๋ฆ")
์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. ์งฑํธํจ! (์ฐธ๊ณ ๋งํฌ)
- UITableView reloadSections๊ณผ IndexSet
๋น๋๊ธฐ
DataSetter์ tryDownload()ํจ์ ์ถ๊ฐํ ์๋ฌ
์๋ฌ ์ํฉ 1.
// ํ
์ด๋ธ๋ทฐ๊ฐ ๋จ๊ธฐ๋์ ์ ์๋ฌ
private func resetTableView(indexPaths: [IndexPath]) {
DispatchQueue.main.sync { [weak self] in
self?.tableView.beginUpdates()
self?.tableView.insertRows(at: indexPaths, with: .automatic)
self?.tableView.endUpdates()
}
}
- ๊ด๋ จ์๋ฌ
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
- ๋ฉ์ธ ์ค๋ ๋์์ ๋๊ธฐ๋ก ์์
์ ์ฒ๋ฆฌํ๊ธฐ๋๋ฌธ์ ๋ฐ๋๋ฝ ๊ฑธ๋ฆผ
- ์๋ DataSetter๊ฐ์ ๊ฐ์ฒด์์ ๋ฐ๋ก URLSession.shared.dataTask๋ฅผ ์ฌ์ฉํ๊ธฐ๋๋ฌธ์ ํด๋น ์ฝ๋์ ์๋ ํด๋ก์ ๋ฅผ ํธ์ถํ๋ ๊ณณ์ด main์ด ์๋ ๋ค๋ฅธ์ค๋ ๋์๊ธฐ๋๋ฌธ์
์๋ฌ ์ํฉ 2.
// ํ
์ด๋ธ๋ทฐ๊ฐ ๋จ์ง๋ง ์ด๋ฏธ์ง๋ ๋จ์ง ์๊ณ UIApplicationMain
private func resetTableView(indexPaths: [IndexPath]) {
DispatchQueue.main.async { [weak self] in
self?.tableView.beginUpdates()
self?.tableView.insertRows(at: indexPaths, with: .automatic)
self?.tableView.endUpdates()
}
}
- ๊ด๋ จ ์๋ฌ
- ์น์
์ ์
๋ฐ์ดํธํ๋ ์์ ์ด ๋ชจ๋ธ ์
๋ฐ์ดํธ ์์ ๊ณผ ๋ง์ง ์์ (async)
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.54.4/UITableView.m:2012
2018-08-06 20:44:29.940777+0900 StoreApp[70331:4708122] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (8 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
ํด๊ฒฐ !
// ํ
์ด๋ธ๋ทฐ๊ฐ ๋จ๊ณ ์๋ฌ๋ ์๋จ
private func resetTableView() {
DispatchQueue.main.async { [unowned self] in
self.tableView.reloadData() // ์ดํ์ reloadSections๋ก ๋ฐ๊ฟ
}
}
- ์๋กญ๊ฒ ์ถ๊ฐ๋์ด์ ๋ฉ์ธ์ค๋ ๋์์ ๋์ํ๋ tryDownload()๋๋ฌธ์ ๊ธฐ์กด์ ์๋ฌ์ํฉ1 ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ๋จ
-
๋ฐ๋ผ์ ํ๋ฒ์ ๋ชจ๋ ํ
์ด๋ธ๋ทฐ๋ฅผ ์ ์ฒด ๋ค reloadํด๋ฒ๋ฆฌ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ๋์์ด ๋๋์ง ํ์ธํจ
storeItems.Swift
func set(with category: Category) {
DataSetter.tryDownload(url: category) { items in
self.update(key: items.keys.first!, value: items.values.first!)
if let firstKey = items.firstKey {
let indexPaths = Array(0..<self.storeItem[firstKey]!.count).map {IndexPath(row: $0, section: firstKey.sectionNumber)}
NotificationCenter.default.post(name: .sectionSetComplete,
object: self,
userInfo: [Keyword.sectionPath : firstKey])//indexPaths])
}
}
// DataSetter.set(with: category) { items in
// self.update(key: items.keys.first!, value: items.values.first!)
// if let firstKey = items.firstKey {
// let indexPaths = Array(0..<self.storeItem[firstKey]!.count).map {IndexPath(row: $0, section: firstKey.sectionNumber)}
// NotificationCenter.default.post(name: .sectionSetComplete,
// object: self,
// userInfo: [Keyword.sectionPath : indexPaths])
// }
// }
}
- insertRows๊ฐ ์๋ reloadSection์ผ๋ก ๋ฐ๊พธ๋ฉด์ category๋ง ๋๊ฒจ์ฃผ๋ฉด ๋จ
RootViewController
class StoreViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
let rowHeightForCell: CGFloat = 100
let rowHeightForHeader: CGFloat = 60
var storeItems = StoreItems()
override func viewDidLoad() {
super.viewDidLoad()
#if DEBUG
self.deleteCache()
#endif
NotificationCenter.default.addObserver(self, selector: #selector(dataReload), name: .reachabilityChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(setComplete(notification:)),name: .sectionSetComplete,object: nil)
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = rowHeightForCell
StoreItems.categories.forEach { (category) in
self.storeItems.set(with: category)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@objc func dataReload() {
if NetworkManager.shared.reachable {
StoreItems.categories.forEach { (category) in
self.storeItems.set(with: category)
}
} else {
print("RootView - dataReload. Not reachable")
}
}
private func resetTableView(indexPaths: Category) {
DispatchQueue.main.async { [weak self] in
// self?.tableView.reloadData()
self?.tableView.reloadSections(IndexSet(0..<(self?.storeItems.storeItem.keys.count)!), with: .automatic)
}
// DispatchQueue.main.sync { [weak self] in
// self?.tableView.beginUpdates()
// self?.tableView.insertRows(at: indexPaths, with: .automatic)
// self?.tableView.endUpdates()
// }
}
@objc func setComplete(notification: Notification) {
guard let userInfo = notification.userInfo else { return }
guard let section = userInfo[Keyword.sectionPath] else { return }
// guard let sectionNumber = section as? [IndexPath] else { return }
guard let category = section as? Category else { return }
self.resetTableView(indexPaths: category)
}
2018.08.07
#if DEBUG
// self.deleteCache()
#endif
// DEBUG
private func deleteCache() {
let cacheURL = ImageSetter.fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
do {
let fileNames = try ImageSetter.fileManager.contentsOfDirectory(atPath: cacheURL.path)
for file in fileNames {
let imageSavingPath = cacheURL.appendingPathComponent(file)
if (file.hasSuffix(".jpg")) {
try ImageSetter.fileManager.removeItem(atPath: imageSavingPath.path)
}
let files = try ImageSetter.fileManager.contentsOfDirectory(atPath: cacheURL.path)
}
} catch {
print("Could not clear temp folder: \(error)")
}
}
2018.08.09
- JKํผ๋๋ฐฑ์ ๋ฆฌ
- RxSwiftโฆ
- KVO์ ๋ฆฌ/์ง๋ฌธ
- NSKeyValueCoding ์๋ ๋ด์ฉ ํฌ์คํ
ํ๊ธฐ
var statusBarView: UIView? {
return value(forKey: "statusBar") as? UIView
}
- NSKeyValueCoding ๋ฉ์ปค๋์ฆ์ผ๋ก ์ธํด ๊ฐ์ฒด์ ์์ฑ์ ์ ๊ทผํ๋ ๋ฉ์ปค๋์ฆ
- ๊ฐ์ฒด ์์ฑ์ด ๋์
๋๋ฆฌ์ ์ ์ฅ๋์ด์๋ค๊ณ ๊ฐ์ ํ๊ณ , key๋ฅผ ์ฃผ๋ฉด value๋ฅผ ์ฃผ๋ ๋ฐฉ์
- (Typically, by convention, the key representing a property is the name of the property itself as it appears in code.)
value(forKey:)
๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ฒด์ ์์ฑ์ ์ด๋ฆ์ด๋ ํค๊ฐ์ผ๋ก ์ฐพ์์ ์ฐธ์กฐํ ์ ์๋๋ฐ, privateํ ์์ฑ๊น์ง ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
- ๊ด๋ จ๋์ด Stackoverflow์ ๋ต๋ณ์์๋ ์ด ๋ฐฉ๋ฒ์ด privateํ ์์ฑ๊น์ง ์ ๊ทผํด์ ์ฐ๋๊ฑฐ๊ธฐ๋๋ฌธ์ ์์ข๋ค๊ณ ํ๋๋ฐ, ๋งค์ปค๋์ฆ์ ์ํด์ privateํ ์์ฑ์ ์ ๊ทผํด์ ๋ฐ๊ฟ๋ฒ๋ฆฌ๋๊ฑฐ๊ธฐ๋๋ฌธ์ ๋ณ๋ก ๊ถ์ฅ๋๋ ๋ฐฉ๋ฒ์ ์๋๋ฏ.
- ์์๋ก statusBar๋ ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์ ๊ทผํด์ ๋ฐ๊พธ๋๊ฒ ๊ถ์ฅ๋๊ณ ์๊ณ ์์ ์๋ statusBar์ ๋ค๋ฅธ๊ณณ์์ ์ ๊ทผํ๋ ์ฝ๋๊ฐ ์์ผ๋ฉด ์ ํ์ด rejectํ๊ธฐ๋ ํ๋ค๊ณ ํ๋ค.
- ๋ ์๋ฃ๋ฅผ ์ฐพ์๋ณผ๋ info.plist์ key-value๋ชฉ๋ก์ฒ๋ผ ์ฐธ๊ณ ์๋ฃ๊ฐ ์์ ์ค ์์๋๋ฐ ์ฐพ๊ณ ์ฐพ์๋ ์๋ ์ด์ ๊ฐ privateํ ์์ฑ์ ์ด๋ฆ๋ค์๋ค ์ด key๋ก์ฐ๋ผ๊ณ ์๋ ค์ค ์ ์์ผ๋๊น(์ฐ๋ผ๊ณ ๊ณต๊ฐํ๋๊ฑฐ ์์ฒด๊ฐ ์ด์ํจ) ๊ทธ๋ฐ๋ฏ.
- ์ปดํ์ผํ์์ด ์๋ ๋ฐํ์์์ ์ ๊ทผํ๋ ๊ฐ์ฒด๋ฅผ ์ง์ ํ๋ค.
value(forKey:)
์ ๋ค์ด๊ฐ๋ ํ๋ผ๋ฏธํฐ๊ฐ ๋ฐํ์์์ ๋ณ๊ฒฝ๋ ์๋ ์๋ค๋ ๋ป.
- (๋ญ..์ต์ง์ค๋ฌ์ด ์ํฉ์ผ ์ ์์ง๋ง A button์ ๋๋ฅด๋ฉด โstatusBarโ๊ฐ ํ๋ผ๋ฏธํฐ๋ก ๋์ด๊ฐ๊ฑฐ๋, B button์ ๋๋ฅด๋ฉด โnavigationBarโ๊ฐ ๋์ด๊ฐ๋ค๊ฑฐ๋โฆ)
- ๊ฐ์ฒด๋ ์์ฑ์ ๋ด๊ฐ ์ ํ key๋ก ์ ๊ทผํ๋๋ก key๋ฅผ ์ธํ
ํ ์ ์๋ค.
setValue(\_:forKey:)
2018.08.10
- ๋งํธ์ฑ ๊ฐ๋ฐํญ๋ชฉ ์ ํ๊ธฐ
- ์ฃผ๋ง ๊ณํ์ธ์ฐ๊ธฐ: ์์์, ๋ธ๋ก๊ทธ์ ๊นํ์ ๋ฆฌ, ๊ธฐ์ด๋ฉด์ ์ง๋ฌธ์ค๋น๋ค
2018.08.11
- ๋ถ์คํธ์ฝ๋ ๋ ์จ์ฑ ๋ค์์ ์ถ
- ์คํ ๋ ์์์ landscape๋ชจ๋์ portrait๋ชจ๋ ๋ค๋ฅด๊ฒ์ ํ๊ธฐ!!!!๋๋์ด์ฐพ์ ์ง์์ ์ฐพ์๋ณผ๊ฑธโฆ.
2018.08.12
BranchTableViewCell
์ setCell()
starbutton์ ์ธํ
ํ๋๋ฐ ์ฒ์ ํ๋ฒ ๋ด์๋ ์ธํ
์ด ๋์ง์๊ณ ์
์ด ํ๋ฉด์์ ๋ฒ์ด๋ฌ๋ค๊ฐ ๋ค์ ๋ํ๋ ๋๋ง ์ธํ
์ด๋จ. ์ฌ์ง์ด ์์ฒญ ๋๋ฆฌ๊ณ ๋๋๋๊นโฆ. ๋ฒํผ ์ด๋ฏธ์ง ์ธํ
ํ๋๊ฑด ๊ฐ๋จํ ์์
์ด๋ผ ์ค๋ ๊ฑธ๋ฆด ๊ฒ ๊ฐ์ง ์์์ ๋ญ๊ฐ ๋ฌธ์ ์ง ํ๊ณ ๊ณ ๋ฏผํ๋ค๊ฐ GCD๋ก main.async๋ก ์์
ํ๊ฒ ๋๋ฆฌ๋๊น ๋นจ๋ผ์ง..!