Swift shapeLayer.fillColor not work in cell contentView - ios

I have a chartView and a customized tableViewcell.
And I try to use chartView add on my tableviewcell.
This ViewController is child ViewController.
I push to this ViewController, and I want to call tapIndexAction(index: 0) to hightlight my bar of index 0.
I also use "tableview didEndDisplaying" can't fill color.
What's wrong with me?
Thanks.
class ChartView: UIView {
let publishSub = PublishSubject<Int?>()
var isAlreadyInit = false
var chartInfo:ChartInfo?
init(info:ChartInfo?, frame:CGRect = CGRect.zero) {
self.chartInfo = info
super.init(frame:frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
if !self.isAlreadyInit {
if self.frame.width > 0 {
self.isAlreadyInit = true
self.drawChart()
}
}
}
func drawChart() {
if let tmpCharInfo = self.chartInfo {
let chartLayer = tmpChartInfo.getChartDrawLayer()
chartLayer.frame = self.bounds
chartLayer.drawChart()
self.layer.addSublayer(chartLayer)
}
}
func tapIndexAction(index: Int) {
if let chartLayer = (self.layer.sublayers?.last) as? ChartLayer {
chartLayer.tapIndex(index: index)
self.publishSub.onNext(index)
}
}
class ChartLayer: CALayer {
var drawInfo:ChartInfo
var touchFrame:[CGRect] = [CGRect]()
var drawLayers:[CAShapeLayer] = [CAShapeLayer]()
var tapIndex:Int?
init(info:ChartDrawInfo) {
self.drawInfo = info
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func tapIndex(index:Int) {
self.tapIndex = index
for idx in 0..<self.touchFrame.count {
let shapeLayer = self.drawLayers[idx]
if idx == index {
shapeLayer.fillColor = UIColor.red.cgColor //Not work in "tableview didEndDisplaying"
}else {
shapeLayer.fillColor = UIColor.blue.cgColor
}
}
}
}
class BarChartTableViewCell: UITableViewCell {
var barChartView: ChartView?
var chartInfo:ChartInfo?
func initCell(drawInfo: ChartInfo?) {
self.chartInfo = drawInfo
if self.barChartView != nil {
for view in self.contentView.subviews {
view.snp.removeConstraints()
view.removeFromSuperview()
}
}
self.barChartView = ChartView(drawInfo: self.chartInfo)
self.contentView.addSubview(barChartView)
barChartView?.snp.makeConstraints({ (make) in
make.left.equalTo(13)
make.top.equalTo(updateTimeLabel.snp.bottom)
make.right.equalToSuperview()
make.height.equalTo(202)
})
}
}
class ViewController: UITableViewDelegate, UITableViewDataSource {
let tableview = UITableView()
tableview.datasource = self
tableview.delegate = self
//numberOfRowInSection return 1
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
if let chartCell = cell as? BarChartTableViewCell {
chartCell.barChartView?.tapIndexAction(index: 0)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let barChartCell = tableView.dequeueReusableCell(withIdentifier: "BarChartTableViewCell", for: indexPath) as! BarChartTableViewCell
barChartCell.initCell(drawInfo: chartInfo)
return barChartCell
}
}

Related

Passing data from UIView to UIViewController using protocol

I'm trying to pass data from UIView contains UITableView to UIViewController but unfortunately, it doesn't work.
Model:
struct Recipes: Codable {
let recipes: [Recipe]
}
struct Recipe: Codable {
let title: String?
let image: String?
let pricePerServing: Double?
let readyInMinutes, servings: Int?
}
The data should be passed from this view
HomeView:
protocol RecipesDetailsSelectActionDelegate: class {
func recipeDetails(recipeTitle: String)
}
class HomeView: UIView {
var recipes: Recipes?
var recipesDetails = [Recipe]()
let indicator = ActivityIndicator()
weak var homeViewDidSelectActionDelegate: HomeViewDidSelectActionDelegate?
weak var recipeDetailsViewSelectActionDelegate: RecipesDetailsSelectActionDelegate?
override init( frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var foodTableView: UITableView = {
let foodTableView = UITableView()
foodTableView.translatesAutoresizingMaskIntoConstraints = false
foodTableView.backgroundColor = .customVeryLightGray()
foodTableView.delegate = self
foodTableView.dataSource = self
foodTableView.register(HomeTableViewCell.self, forCellReuseIdentifier: "HomeTableViewCell")
foodTableView.rowHeight = UITableView.automaticDimension
foodTableView.estimatedRowHeight = 100
foodTableView.showsVerticalScrollIndicator = false
foodTableView.separatorStyle = .none
return foodTableView
}()
}
extension HomeView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipesDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let url = URL(string: recipesDetails[indexPath.row].image ?? "Error")
cell.foodImage.kf.setImage(with: url)
cell.foodTitle.text = recipesDetails[indexPath.row].title
if let readyInMin = recipesDetails[indexPath.row].readyInMinutes {
cell.cookingTimeInfoLabel.text = "\(readyInMin) Minutes"
}
if let pricePerServing = recipesDetails[indexPath.row].pricePerServing {
cell.priceInfoLabel.text = String(format: "%.2f", pricePerServing / 100)
}
if let serving = recipesDetails[indexPath.row].servings {
cell.servesInfoLabel.text = "\(serving)"
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
recipeDetailsViewSelectActionDelegate?.recipeDetails(recipeTitle: recipesDetails[indexPath.row].title ?? "Error")
}
}
HomeViewController:
class HomeViewController: UIViewController {
lazy var mainView: HomeView = {
let view = HomeView(frame: self.view.frame)
view.recipeDetailsViewSelectActionDelegate = self
return view
}()
override func loadView() {
super.loadView()
view = mainView
}
}
extension HomeViewController: RecipesDetailsSelectActionDelegate {
func recipeDetails(recipeTitle: String) {
let vc = RecipesDetailsViewController()
vc.mainView.recipeTitle = recipeTitle
self.show(vc, sender: nil)
}
}
The data should be passed to this view
RecipesDetailsView:
class RecipesDetailsView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var recipeTitle: String?
lazy var tableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
tableView.showsVerticalScrollIndicator = false
tableView.separatorStyle = .none
tableView.backgroundColor = .white
tableView.register(IngredientsTableViewCell.self, forCellReuseIdentifier: "IngredientsTableViewCell")
return tableView
}()
extension RecipesDetailsView: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "IngredientsTableViewCell", for: indexPath) as! IngredientsTableViewCell
cell.recipeTitleLabel.text = recipeTitle
return cell
}
}
RecipesDetailsViewController:
class RecipesDetailsViewController: UIViewController {
lazy var mainView: RecipesDetailsView = {
let view = RecipesDetailsView(frame: self.view.frame)
view.backgroundColor = .white
return view
}()
override func loadView() {
super.loadView()
view = mainView
}
}

TableView inside a custom UITableViewCell not appearing for all of the cells of that custom cellviewtype

I am trying to create a table of services such that, if service has a couple of sub-services, then the cell associated with that service then has another table view showing those sub-services under the said service.
I tried implementing such a table by looking at the example shown in the link: table within a tableviewcell
I am posting related source codes associated with the tableview
BookingServiceChargeViewCell.swift
import UIKit
import PineKit
import SwiftMoment
class BookingServiceChargeViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
var service : Service? = nil
var subServices : [Service] = []
let content = PineCardView()
var cover = UIImageView()
let serviceName = PineLabel.Bold(text: " ... ")
var itemIndex = -1
var chosen = false
var parentView : OnboardingChosenServicesViewController? = nil
var anchor = UIView()
let table = UITableView()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = .none
layout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func layout() {
self.addSubview(content)
content.snp.makeConstraints { (make) in
make.top.left.right.equalTo(self).inset(5)
make.bottom.equalTo(self)
}
layoutContent()
}
func layoutContent() {
content.addSubviews([cover, serviceName])
self.cover.image = UIImage(named: "gray-card")
cover.clipsToBounds = true
cover.snp.makeConstraints { (make) in
make.width.equalTo(content).multipliedBy(0.15)
make.left.equalTo(content).offset(10)
make.top.equalTo(content.snp.top).offset(15)
make.size.equalTo(50)
}
serviceName.textColor = UIColor.black
serviceName.font = Config.Font.get(.Bold, size: 17.5)
serviceName.snp.makeConstraints { (make) in
make.centerY.equalTo(cover)
make.left.equalTo(cover.snp.right).offset(20)
}
table.delegate = self
table.dataSource = self
table.register(BookingSubServicesChargeViewCell.self, forCellReuseIdentifier: "cell")
table.separatorStyle = .none
self.content.addSubview(table)
table.snp.makeConstraints { (make) in
make.top.equalTo(self.cover.snp.bottom).offset(15)
make.left.equalTo(self.cover.snp.right).offset(10)
make.right.equalTo(self.content.snp.right).offset(-10)
make.height.equalTo(450)
}
}
func configure(_ service: Service, subServices: [Service], index: Int, parentView: OnboardingChosenServicesViewController) {
self.service = service
self.subServices = subServices
self.itemIndex = index
self.parentView = parentView
if (self.service!.defaultImage != nil){
ImageLoader.sharedLoader.imageForUrl(urlString: self.service!.defaultImage!) { (image, url) in
self.cover.image = image
}
}
self.serviceName.text = self.service!.name!
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.subServices.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BookingSubServicesChargeViewCell
cell.configure(self.subServices[indexPath.row], index: indexPath.row, parentView: self.parentView!)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
BookingSubServicesChargeViewCell.swift
import UIKit
import PineKit
import SwiftMoment
class BookingSubServicesChargeViewCell: UITableViewCell {
var service : Service? = nil
let content = PineCardView()
var cover = UIImageView()
let serviceName = PineLabel.Bold(text: " ... ")
var itemIndex = -1
var chosen = false
var parentView : OnboardingChosenServicesViewController? = nil
var anchor = UIView()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = .none
layout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func layout() {
self.addSubview(content)
content.snp.makeConstraints { (make) in
make.top.left.right.equalTo(self).inset(5)
make.bottom.equalTo(self)
}
layoutContent()
}
func layoutContent() {
content.addSubviews([cover, serviceName])
self.cover.image = UIImage(named: "gray-card")
cover.clipsToBounds = true
cover.snp.makeConstraints { (make) in
make.width.equalTo(content).multipliedBy(0.15)
make.left.equalTo(content).offset(10)
make.top.equalTo(content.snp.top).offset(15)
make.size.equalTo(50)
}
serviceName.textColor = UIColor.black
serviceName.font = Config.Font.get(.Bold, size: 17.5)
serviceName.snp.makeConstraints { (make) in
make.centerY.equalTo(cover)
make.left.equalTo(cover.snp.right).offset(20)
}
self.anchor = self.serviceName
}
func configure(_ service: Service, index: Int, parentView: OnboardingChosenServicesViewController) {
self.service = service
self.itemIndex = index
self.parentView = parentView
if (self.service!.defaultImage != nil){
ImageLoader.sharedLoader.imageForUrl(urlString: self.service!.defaultImage!) { (image, url) in
self.cover.image = image
}
}
self.serviceName.text = self.service!.name!
}
}
Here a couple of screenshots of the situation that has arisen:-
As you can see in the screenshots, some of the tables which have sub-services are not being shown, but sometimes they are being shown.
Can someone tell me what is it that I am missing here? What changes am I supposed to make in the source codes shown above?
FYI: I am not using storyboards in any way and I do not know what nib files are. I have constructed this programmatically and I am hoping that I can get a code snippet based solution as soon as possible.
Thanks.
In BookingServiceChargeViewCell class, call self.table.reloadData() at the end of configure method as below.
func configure(_ service: Service, subServices: [Service], index: Int, parentView: OnboardingChosenServicesViewController) {
self.service = service
self.subServices = subServices
self.itemIndex = index
self.parentView = parentView
if (self.service!.defaultImage != nil){
ImageLoader.sharedLoader.imageForUrl(urlString: self.service!.defaultImage!) { (image, url) in
self.cover.image = image
}
}
self.serviceName.text = self.service!.name!
self.table.reloadData()
}

swift tableView in custom view programatically - losing reference to controllers delegate and data source

I am trying to learn MVVM pattern and writing all my views programatically using Snapkit. I am creating hamburger menu which consist of simple tableView and I have a problem, that my tableView in cusom view is losing delegate and data source references on the view controller. I also tried using UITableViewController, but result is the same, here is my code:
ViewModel:
class SideMenuViewModel {
let cellId = "SideMenuCellId"
weak var delegate: SideMenuViewModelDelegate?
private let cells: [SideMenuItemStruct] = [SideMenuItemStruct(type: .allDogs, title: "ALL DOGOS"),
SideMenuItemStruct(type: .randomDog, title: "RANDOM DOGO")]
init(delegate: SideMenuViewModelDelegate) {
self.delegate = delegate
}
var numberOfRows: Int {
return cells.count
}
func selectedMenuItem(indexPath: IndexPath) {
switch SideMenuItemsEnum(rawValue: indexPath.row) {
case .allDogs?:
delegate?.selectedMenuItem(selectedItem: SideMenuItemsEnum.allDogs)
case .randomDog?:
delegate?.selectedMenuItem(selectedItem: SideMenuItemsEnum.randomDog)
default:
print("error when choosing menu item")
}
}
func cellForRow(_ tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? SideMenuCell else {
fatalError("could not deque Side menu cell")
}
cell.selectionStyle = .none
cell.setUpCell(sideMenuItem: cells[indexPath.row])
return cell
}
}
View:
class SideMenuView: UIView {
var sideMenuTableView = UITableView()
let sideMenuButton = UIButton(type: .system)
weak var delegate: UITableViewDelegate? {
get {
return sideMenuTableView.delegate
}
set {
sideMenuTableView.delegate = newValue
}
}
weak var dataSource: UITableViewDataSource? {
get {
return sideMenuTableView.dataSource
}
set {
sideMenuTableView.dataSource = newValue
}
}
override init(frame: CGRect) {
super.init(frame: frame)
initUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
}
private func initUI() {
addSubview(sideMenuButton)
addSubview(sideMenuTableView)
setUpSideMenuButton()
setUpSideMenuTableView()
}
private func setUpSideMenuButton() {
sideMenuButton.setTitle("DELEGATE", for: .normal)
sideMenuButton.addTarget(self, action: #selector(buttonPrint), for: .touchUpInside)
sideMenuButton.snp.makeConstraints { (make) in
make.top.equalTo(self)
make.centerX.equalTo(self)
}
}
#objc func buttonPrint() {
print("delegate: \(String(describing: sideMenuTableView.delegate)), data source: \(String(describing: sideMenuTableView.dataSource))")
}
private func setUpSideMenuTableView() {
sideMenuTableView.snp.makeConstraints { (make) in
make.top.equalTo(sideMenuButton.snp.bottom)
make.bottom.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
}
}
}
And my View Controller:
class SideMenuController: UIViewController {
fileprivate let viewModel: SideMenuViewModel
fileprivate var sideMenuView: SideMenuView {
return view as! SideMenuView
}
init(viewModel: SideMenuViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
override func loadView() {
let sideMenuView = SideMenuView()
sideMenuView.sideMenuTableView.delegate = self
sideMenuView.sideMenuTableView.dataSource = self
view = sideMenuView
}
override func viewDidLoad() {
super.viewDidLoad()
sideMenuView.sideMenuTableView.register(SideMenuCell.self, forCellReuseIdentifier: viewModel.cellId)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SideMenuController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.numberOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return viewModel.cellForRow(tableView, indexPath: indexPath)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
viewModel.selectedMenuItem(indexPath: indexPath)
print("awd")
}
}
Simulater after init
Simulator after scroll
DELEGATE button tapped result
I am learning from few tutorials and they didn't had this problem, but they were all using Interface builders, which I want to avoid. Please, let me know, if I am doing something really wrong, thanks.
SOLUTION
I found out, I made a really huge mistake outside of this showed code, I initialized SideMenuController in a function and didn't keep reference to it, so naturaly it was automaticly deinitialized after end of a function. It was a really bad mistake. Thanks for all answers, code here is working, but I refactored it according to answer.
I guess you have been hacking on this for a while and it looks like code has ended up a bit all over the place.
If you are going to follow MVVM then you need to think about the role of each component.
Model - An array of SideMenuItem
ViewModel - In this case it is the same as your Model so you can dispense with the Model and just use the ViewModel. In more complex examples, the ViewModel maps back to the Model, exposing on the data required by the view and performing any required translations
View - The actual visual elements; In this case just a tableview (although you also have a button for debugging)
Finally, you still have the View Controller that brings it all together
ViewModel
struct SideMenuViewModel {
let items = [SideMenuItemStruct(type: .allDogs, title: "ALL DOGOS"),
SideMenuItemStruct(type: .randomDog, title: "RANDOM DOGO")]
}
View
class SideMenuView: UIView {
weak var viewModel: SideMenuViewModel?
weak var delegate: SideMenuViewDelegate? // Was SideMenuViewModelDelegate
private let sideMenuButton = UIButton(type: .system)
private var sideMenuTableView = UITableView()
private let cellId = "YourCellID"
override init(frame: CGRect) {
super.init(frame: frame)
initUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
}
private func initUI() {
addSubview(sideMenuButton)
addSubview(sideMenuTableView)
setUpSideMenuButton()
setUpSideMenuTableView()
}
private func setUpSideMenuButton() {
sideMenuButton.setTitle("DELEGATE", for: .normal)
sideMenuButton.addTarget(self, action: #selector(buttonPrint), for: .touchUpInside)
sideMenuButton.snp.makeConstraints { (make) in
make.top.equalTo(self)
make.centerX.equalTo(self)
}
}
#objc func buttonPrint() {
print("delegate: \(String(describing: sideMenuTableView.delegate)), data source: \(String(describing: sideMenuTableView.dataSource))")
}
private func setUpSideMenuTableView() {
sideMenuTableView.snp.makeConstraints { (make) in
make.top.equalTo(sideMenuButton.snp.bottom)
make.bottom.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
}
sideMenuTableView.datasource = self
sideMenuTableView.delegate = self
sideMenuTableView.register(SideMenuCell.self, forCellReuseIdentifier: cellId)
}
}
extension SideMenuView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel?.numberOfRows ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? SideMenuCell else {
fatalError("could not deque Side menu cell")
}
cell.selectionStyle = .none
cell.setUpCell(sideMenuItem: self.viewModel!.items[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let menuItem = self.viewModel!.items[indexPath.row]
self.delegate?.didSelect(menuItem)
}
}
ViewController
class SideMenuController: UIViewController {
fileprivate let viewModel: SideMenuViewModel
fileprivate var sideMenuView: SideMenuView {
return view as! SideMenuView
}
override func loadView() {
let sideMenuView = SideMenuView()
sideMenuView.delegate = self
sideMenuView.viewModel = viewModel
view = sideMenuView
}
init(viewModel: SideMenuViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SideMenuController: SideMenuViewDelegate {
// TODO: Implement delegate method for menu selection
}

Swift custom UIView IBOutlet nil , awakeFromNib() never called

I am trying to custom a UIView but when I call it, the outlets of custom view always nil, and awakeFromNib() never called, too. Here my CustomView:
class DropdownMenuView: UIView {
//MARK: Outlets
#IBOutlet var view: DropdownMenuView!
#IBOutlet weak var fadeView: UIView!
#IBOutlet weak var tableView: UITableView!
var selection:Selection = .Default
var iconType:IconType = .Default
var menuTitles:[String] = []
var cellHeight:CGFloat = 44
var textColorNomal:UIColor = UIColor.blackColor()
var textColorHighlight:UIColor = UIColor.redColor()
var isShown: Bool!
//MARK: Lifecycle
override func awakeFromNib() {
print("awakeFromNib")
super.awakeFromNib()
initSubviews()
configView()
}
override func layoutSubviews() {
super.layoutSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
func initSubviews() {
if let nibsView = NSBundle.mainBundle().loadNibNamed("DropdownMenuView", owner: self, options: nil) as? [UIView] {
let nibRoot = nibsView[0]
self.addSubview(nibRoot)
nibRoot.frame = self.bounds
}
}
required init(uSelection: Selection = Selection.Default, uIconType:IconType = IconType.Default, uMenuTitles:[String]) {
self.selection = uSelection
self.iconType = uIconType
self.menuTitles = uMenuTitles
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
}
private func configView() {
switch (selection) {
case Selection.Multiple:
tableView.allowsMultipleSelection = true
default:
tableView.allowsMultipleSelection = false
}
tableView.registerNib(UINib(nibName: "DropdownMenuCell", bundle: nil), forCellReuseIdentifier: "DropdownMenuCell")
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
hideMenu()
}
internal func show() {
if self.isShown == false {
self.showMenu()
}
}
internal func hide() {
if self.isShown == true {
self.hideMenu()
}
}
func showMenu() {
self.isShown = true
if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {
window.bringSubviewToFront(self)
}
// Animation
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.alpha = 1
})
}
func hideMenu() {
self.isShown = false
// Animation
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.alpha = 0
})
}
}
//MARK: UITableViewDelegate methods
extension DropdownMenuView: UITableViewDelegate {
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat(menuTitles.count) * cellHeight
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return cellHeight
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DropdownMenuCell") as! DropdownMenuCell
cell.lblTitle.text = menuTitles[indexPath.row]
cell.iconType = iconType
return cell
}
}
//MARK: UITableViewDataSource methods
extension DropdownMenuView: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuTitles.count
}
}
I tried to remove outlets and connect again, but I wasn't lucky. It isn't working anymore. You can check my full demo project here:
https://www.dropbox.com/s/5udbl2kn9vnwjar/ModuleDemo.zip?dl=0
You click on "Label" on StartVC to call custom UIView.
I hope what I ask is possible. Any helps always are appropriate!

Thread 5: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) - Cast from 'Result<AnyObject>' to unrelated type 'NSDictionary' always fail

I am following the Ray Wenderlich tutorial on Alamofire (and struggling), http://www.raywenderlich.com/85080/beginning-alamofire-tutorial#comments , and I am getting the error in the title, in the "loading more photos" part.
The error is on the line "let photoInfos = ((JSON as! NSDictionary).valueForKey("photos") as! [NSDictionary]).filter ({"
Here is my code.
//
// PhotoBrowserCollectionViewController.swift
// Photomania
//
// Created by Essan Parto on 2014-08-20.
// Copyright (c) 2014 Essan Parto. All rights reserved.
//
import UIKit
import Alamofire
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var photos = NSMutableArray()
#IBOutlet weak var PhotoBrowserCell: PhotoBrowserCollectionViewCell!
let refreshControl = UIRefreshControl()
var populatingPhotos = false
var currentPage = 1
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
let PhotoBrowserFooterViewIdentifier = "PhotoBrowserFooterView"
// MARK: Life-cycle
override func viewDidLoad() {
super.viewDidLoad()
setupView()
populatePhotos()
//// Alamofire.request(.GET, "https://api.500px.com/v1/photos").responseJSON() {
//// (_, _, data) in
//// print(data.value)}
//
// Alamofire.request(.GET, "https://api.500px.com/v1/photos", parameters: ["consumer_key": "Jj0vPllqD0zvxttgFZ1aTbRF5zy9g1yDcsTxJRFV"]).responseJSON() {
// (_,_,JSON) in
// print(JSON.value)
//
// let photoInfos = (JSON.value!.valueForKey("photos") as! [NSDictionary]).filter({
// ($0["nsfw"] as! Bool) == false
// }).map {
// PhotoInfo(id: $0["id"] as! Int, url: $0["image_url"] as! String)
// }
//
// self.photos.addObject(photoInfos)
// print(self.photos)
//
// self.collectionView?.reloadData()
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: CollectionView
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photos.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
// let imageURL = (photos.objectAtIndex(indexPath.row) as! PhotoInfo).url
let imageURL = (photos.objectAtIndex(indexPath.row) as! PhotoInfo).url
Alamofire.request(.GET, imageURL).response() {
(_,_, data, _) in
let image = UIImage(data: data!)
cell.imageView.image = image
}
return cell
}
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
return collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PhotoBrowserFooterViewIdentifier, forIndexPath: indexPath)
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ShowPhoto", sender: (self.photos.objectAtIndex(indexPath.item) as! PhotoInfo).id)
}
// MARK: Helper
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width - 2) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
layout.footerReferenceSize = CGSize(width: collectionView!.bounds.size.width, height: 100.0)
collectionView!.collectionViewLayout = layout
navigationItem.title = "Featured"
collectionView!.registerClass(PhotoBrowserCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
collectionView!.registerClass(PhotoBrowserCollectionViewLoadingCell.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: PhotoBrowserFooterViewIdentifier)
refreshControl.tintColor = UIColor.whiteColor()
refreshControl.addTarget(self, action: "handleRefresh", forControlEvents: .ValueChanged)
collectionView!.addSubview(refreshControl)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowPhoto" {
(segue.destinationViewController as! PhotoViewerViewController).photoID = sender!.integerValue
(segue.destinationViewController as! PhotoViewerViewController).hidesBottomBarWhenPushed = true
}
}
// 1
override func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y + view.frame.size.height > scrollView.contentSize.height * 0.8 {
populatePhotos()
}
}
func populatePhotos() {
// 2
if populatingPhotos {
return
}
populatingPhotos = true
// 3
Alamofire.request(Five100px.Router.PopularPhotos(self.currentPage)).responseJSON() {
(_, _, JSON) in
// 4
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
// 5, 6, 7
let photoInfos = ((JSON as! NSDictionary).valueForKey("photos") as! [NSDictionary]).filter ({
($0["nsfw"] as! Bool) == false }).map { PhotoInfo(id: $0["id"] as! Int, url: $0["image_url"] as! String)}
//8
let lastItem = self.photos.count
//9
self.photos.addObject(photoInfos)
//10
let indexPaths = (lastItem..<self.photos.count).map { NSIndexPath(forItem: $0, inSection: $0) }
// 11
dispatch_async(dispatch_get_main_queue()) {
self.collectionView!.insertItemsAtIndexPaths(indexPaths)
}
self.currentPage++
}
self.populatingPhotos = false
}
}
func handleRefresh() {
}
}
class PhotoBrowserCollectionViewCell: UICollectionViewCell {
let imageView = UIImageView()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor(white: 0.1, alpha: 1.0)
imageView.frame = bounds
addSubview(imageView)
}
}
class PhotoBrowserCollectionViewLoadingCell: UICollectionReusableView {
let spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
spinner.startAnimating()
spinner.center = self.center
addSubview(spinner)
}
}
the answer is very simple. On the Five100px.swift file , you will see static let consumerKey. please update consumerKey. If you live to continue same problem. please download new version https://www.dropbox.com/s/e2unowffetv9h9c/Photomania.zip?dl=0 from this link.

Resources