I need to create this view by calling it from another view, I need to be able to create the view without the appdelegate. I need help with this. Thanks
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
SampleData.createSampleData()
let graph = Graph()
let search = Search<Entity>(graph: graph).for(types: "Category")
var viewControllers = [PostsViewController]()
for category in search.sync() {
if let name = category["name"] as? String {
viewControllers.append(PostsViewController(category: name))
}
}
let pageTabBarController = AppPageTabBarController(viewControllers: viewControllers)
let toolbarController = AppToolbarController(rootViewController: pageTabBarController)
let menuController = AppMenuController(rootViewController: toolbarController)
let leftViewController = LeftViewController()
let navigationDrawerController = NavigationDrawerController(rootViewController: menuController,
leftViewController: leftViewController
)
window = UIWindow(frame: Screen.bounds)
window!.rootViewController = navigationDrawerController
window!.makeKeyAndVisible()
return true
}
**This is my code, crash all time **
import UIKit
import Material
import Graph
class ViewController:PageTabBarController {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
open override func prepare() {
super.prepare()
SampleData.createSampleData()
let graph = Graph()
let search = Search<Entity>(graph: graph).for(types: "Category")
var viewControllers = [PostsViewController]()
for category in search.sync() {
if let name = category["name"] as? String {
viewControllers.append(PostsViewController(category: name))
}
}
let pageTabBarController = AppPageTabBarController(viewControllers: viewControllers)
let toolbarController = AppToolbarController(rootViewController: pageTabBarController)
let menuController = AppMenuController(rootViewController: toolbarController)
let leftViewController = LeftViewController()
let navigationDrawerController = NavigationDrawerController(rootViewController: menuController,
leftViewController: leftViewController
)
window = UIWindow(frame: Screen.bounds)
window!.rootViewController = navigationDrawerController
window!.makeKeyAndVisible()
}
}
extension ViewController: PageTabBarControllerDelegate {
func pageTabBarController(_ pageTabBarController: PageTabBarController, didTransitionTo viewController: UIViewController) {
}
}
Related
I'm getting this error in the AppDelegate, but I'm not sure what the problem might be. Any help is appreciated, thanks!
(the exact line that has the error is: "let detailsViewModel = DetailsJobView(details: details)" in the "private func loadDetails" section)
Btw, the error underlines the "d" in the second "details" in (details: details)
I've noted it in the code, but it might be hard to find.
import UIKit
import Firebase
import CoreLocation
import Moya
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let window = UIWindow()
let locationService = LocationService()
let homeStoryboard = UIStoryboard(name: "Home", bundle: nil)
let service = MoyaProvider<YelpService.BusinessesProvider>()
let jsonDecoder = JSONDecoder()
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Change color of tab bar items
UITabBar.appearance().tintColor = .black
FirebaseApp.configure()
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
locationService.didChangeStatus = { [weak self] success in
if success {
self?.locationService.getLocation()
}
}
locationService.newLocation = { [weak self] result in
switch result {
case .success(let location):
self?.loadJobs(with: location.coordinate)
case .failure(let error):
assertionFailure("Error getting the users location \(error)")
}
}
switch locationService.status {
case .notDetermined, .denied, .restricted:
let locationViewController = homeStoryboard.instantiateViewController(withIdentifier: "LocationViewController") as? LocationViewController
locationViewController?.delegate = self
window.rootViewController = locationViewController
default:
let nav = homeStoryboard
.instantiateViewController(withIdentifier: "JobNavigationController") as? UINavigationController
self.navigationController = nav
window.rootViewController = nav
locationService.getLocation()
(nav?.topViewController as? JobTableViewController)?.delegete = self
}
window.makeKeyAndVisible()
return true
}
private func loadDetails(for viewController: UIViewController, withId id: String) {
service.request(.details(id: id)) { [weak self] (result) in
switch result {
case .success(let response):
guard let strongSelf = self else { return }
if let details = try? strongSelf.jsonDecoder.decode(Details.self, from: response.data) {
let detailsViewModel = DetailsJobView(details: details) //ERROR IS HERE
(viewController as? DetailsJobViewController)?.viewModel = detailsViewModel
}
case .failure(let error):
print("Failed to get details \(error)")
}
}
}
private func loadJobs(with coordinate: CLLocationCoordinate2D) {
service.request(.search(lat: coordinate.latitude, long: coordinate.longitude)) { [weak self] (result) in
guard let strongSelf = self else { return }
switch result {
case .success(let response):
let root = try? strongSelf.jsonDecoder.decode(Root.self, from: response.data)
let viewModels = root?.jobs
.compactMap(JobListViewModel.init)
.sorted(by: { $0.distance < $1.distance })
if let nav = strongSelf.window.rootViewController as? UINavigationController,
let jobListViewController = nav.topViewController as? JobTableViewController {
jobListViewController.viewModels = viewModels ?? []
} else if let nav = strongSelf.homeStoryboard
.instantiateViewController(withIdentifier: "JobNavigationController") as? UINavigationController {
strongSelf.navigationController = nav
strongSelf.window.rootViewController?.present(nav, animated: true) {
(nav.topViewController as? JobTableViewController)?.delegete = self
(nav.topViewController as? JobTableViewController)?.viewModels = viewModels ?? []
}
}
case .failure(let error):
print("Error: \(error)")
}
}
}
}
extension AppDelegate: LocationActions, ListActions {
func didTapAllow() {
locationService.requestLocationAuthorization()
}
func didTapCell(_ viewController: UIViewController, viewModel: JobListViewModel) {
loadDetails(for: viewController, withId: viewModel.id)
}
}
Here is the DetailsJobView as requested by #heitormurara:
import UIKit
import MapKit
#IBDesignable class DetailsJobView: CoreView {
#IBOutlet weak var collectionView: UICollectionView?
#IBOutlet weak var pageControl: UIPageControl?
#IBOutlet weak var priceLabel: UILabel?
#IBOutlet weak var hoursLabel: UILabel?
#IBOutlet weak var locationLabel: UILabel?
#IBOutlet weak var ratingsLabel: UILabel?
#IBOutlet weak var mapView: MKMapView?
#IBAction func handleControl(_ sender: UIPageControl) {
}
}
My guess is you are trying to instance a UIView child in an improper way. Try initialising it without arguments and having your details variable as a public variable:
let detailsViewModel = DetailsJobView()
detailsViewModel.details = details
Also, you need to create the variable details in your DetailsJobView:
import UIKit
import MapKit
#IBDesignable class DetailsJobView: CoreView {
...
var details: Details?
I am trying to 'preview' a view controller through 3D touch. The code, as it is, does work, however the exiting preview animation is jittery and the following error pops up on the terminal.
2019-07-16 11:22:51.049757+0100 VisualisationsUIKit[439:29734] [Common] _BSMachError: port d90f; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
Some googling showed me that this error often goes away if you remove all breakpoints or change the 'Localization native development region' in info.plist but neither helped.
The code for the 'peak & pop' is below:
//PEAK & POP
extension ViewController: UIViewControllerPreviewingDelegate {
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
let selectedVis = filteredVisualisations[indexPath.row]
//guard let cell = tableView.cellForRow(at: indexPath) as? TableViewCell else { return nil}
let identifier = "GIFViewController"
guard let GIFVC = storyboard?.instantiateViewController(withIdentifier: identifier) as? GIFViewController else { return nil}
GIFVC.selection = selectedVis
GIFVC.preferredContentSize = CGSize(width: 0, height: 190)
return GIFVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
let selectedVis = (viewControllerToCommit as! GIFViewController).selection
let identifier = "DetailViewController"
//force unwrap?
let detailVC = storyboard!.instantiateViewController(withIdentifier: identifier) as! DetailViewController
detailVC.selectedVis = selectedVis
self.show(detailVC, sender: self)
}
}
//PREVIEW VIEW CONTROLLER
import UIKit
import SDWebImage
class GIFViewController: UIViewController {
#IBOutlet weak var GIFView: UIImageView!
var selection = visualisations[0]
override func viewDidLoad() {
super.viewDidLoad()
//GIFView.loadGif(name: selection.name + "_gif")
GIFView.sd_setImage(with: URL(string: selection.gifURL))
// Do any additional setup after loading the view.
}
override func viewDidDisappear(_ animated: Bool = true) {
SDImageCache.shared.clearMemory()
}
deinit {
print("DEALLOCATED GIFViewController class")
}
}
I would like to change an icon of my tabbar from the appDelegate.
I will explain why I want to do that.
From my website I send data by push to my application, so in the appdelegate I recieve the data in the function didReceiveRemoteNotification, with these data I create a local notification manually. I would also like to be able to modify the icon of my TabBar to show that there is a new notification.
So how to change the icon of the tabbar from the app delegate?
Here is a photo of my app, the green circle is the part that means "New notification"
My App images
Here my code in appdelegate:
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable: Any]) {
if let data = data as? NSDictionary {
print("Title: \(data)")
LocalNotification.createLocalNotificationWithIntervals(identifier: "Push",
title: data["title"] as! String,
body: data["body"] as! String,
intervals: 1) { error in
guard error == nil else {
print("Error: \(error!.localizedDescription)")
return
}
print("Successfully execute notification")
}
}
}
I user a tabor controller:
class FittoTabBarController: UITabBarController {
let kImageNoLabelInset: CGFloat = 6.0
var selectedTab: FittoTabBar.Tabs = .pods {
didSet {
selectedIndex = selectedTab.rawValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
selectedTab = .pods
removeItemsTitles()
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let selectedItemIndex = tabBar.items?.index(of: item),
let selectedTab = FittoTabBar.Tabs(rawValue: selectedItemIndex) else {
return
}
self.selectedTab = selectedTab
}
private func removeItemsTitles() {
if let items = self.tabBar.items {
for item in items {
item.title = ""
item.imageInsets = UIEdgeInsets(top: kImageNoLabelInset, left: 0.0, bottom: -kImageNoLabelInset, right: 0.0)
}
}
}
The input of my application is on the tabbar controller
With the code provided above, You need to follow these steps to make it working.
In your FittoTabBarController add these methods.
func setBadge(_ value: String?) {
_ = self.viewControllers![2].tabBarItem.badgeValue = value
}
func getBadge() -> String? {
return self.viewControllers![2].tabBarItem.badgeValue
}
func resetBadge() {
self.viewControllers![2].tabBarItem.badgeValue = nil
}
In your appDelegate, get the rootViewController of your window, on receiving notification
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable: Any]) {
if let data = data as? NSDictionary {
print("Title: \(data)")
let myTabBarController = self.window?.rootViewController as! FittoTabBarController
var newBadgeCount = "1"
if let currentBadgeCount = myTabBarController.getBadge() {
// Convert to int
var intValOfCurrentBadge = Int(currentBadgeCount)!
// Increaset it by one.
intValOfCurrentBadge = intValOfCurrentBadge + 1
// Convert back to string.
newBadgeCount = "\(intValOfCurrentBadge)"
}
// Set your badge value here.
myTabBarController.setBadge(newBadgeCount)
// ADD YOUR EXISTING CODE HERE
}
}
when user clicks on the 3rd tab, just call the resetBadge() method to remove the badge count.
Hope it helps.
I've tried everything to get a tabbar controller onto MainViewController and nothing seems to work.
Just a quick rundown on how app works:
Storyboard entry is AppContainerViewController and if user is logged in then MainViewController appears as it should however I can't get MainVC to become a TabBar controller to display tab bar for user navigation to various pages.
What am I doing wrong?!
appcontainerviewcontroller
class AppContainerViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
AppManager.shared.appContainer = self
AppManager.shared.showApp()
}
}
import UIKit
import Firebase
import FirebaseDatabase
import FBSDKLoginKit
class AppManager {
static let shared = AppManager()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var appContainer: AppContainerViewController!
private init() {}
func showApp() {
var viewController: UIViewController
if (Auth.auth().currentUser == nil) && (FBSDKAccessToken.current() == nil) {
viewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
} else {
viewController = storyboard.instantiateViewController(withIdentifier: "MainViewController")
}
appContainer.present(viewController, animated: true, completion: nil)
}
func logout() {
let loginManager = FBSDKLoginManager()
loginManager.logOut()
try! Auth.auth().signOut()
appContainer.presentedViewController?.dismiss(animated: true, completion: nil)
}
}
main view controller
import UIKit
import Firebase
import FirebaseDatabase
import FBSDKShareKit
class MainViewController: UIViewController {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var email: UILabel!
#IBAction func logoutPressed(_ sender: Any) {
AppManager.shared.logout()
}
#IBAction func fbSharePressed(_ sender: Any) {
let content = FBSDKShareLinkContent()
content.contentURL = URL(string: "https://advice.com")
content.quote = "Hey, I'm one step closer to getting into the college of my dreams with this app. Download it and let's go together!"
let dialog : FBSDKShareDialog = FBSDKShareDialog()
dialog.fromViewController = self
dialog.shareContent = content
dialog.mode = FBSDKShareDialogMode.automatic
dialog.show()
}
func userProfile() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let ref = Database.database().reference()
ref.child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dict = snapshot.value as? [String: Any] else { return }
let user = CurrentUserProfile(uid: uid, dictionary: dict)
self.name.text = user.name
self.email.text = user.email
}, withCancel: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
userProfile()
}
}
Egg on my face. My storyboard IDs were wrong and Embedding MainViewController into a TabBarController via the storyboard and then applying MainVC's storyboard ID to the TabBarController did the trick.
I have a simple one file menu bar app in swift:
import Cocoa
class StatusBarApp : NSObject {
func buildMenu() {
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
statusItem.title = "StatusBarApp"
let menu = NSMenu()
let aboutMenuItem = NSMenuItem()
aboutMenuItem.title = "About"
aboutMenuItem.target = self
aboutMenuItem.action = #selector(about)
menu.addItem(aboutMenuItem)
statusItem.menu = menu
}
func about() {
print("XXX")
}
}
NSApplication.sharedApplication()
StatusBarApp().buildMenu()
NSApp.run()
I can't make the "About" menu bar item to connected to the about() function. When I run the app, the "About" item is disabled.
How do I pass the selector to menu item action in Swift 2.2? Thanks
The selector is supposed to have a parameter (the NSMenuItem instance)
aboutMenuItem.action = #selector(StatusBarApp.about(_:))
...
func about(sender : NSMenuItem) {
print("XXX")
}
Edit:
The solution is to run the app as full Cocoa app including its delegate.
I added a second menu item to terminate the app.
import Cocoa
class StatusBarApp : NSObject, NSApplicationDelegate {
var statusItem : NSStatusItem!
func applicationDidFinishLaunching(aNotification: NSNotification) {
statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
statusItem.title = "StatusBarApp"
let menu = NSMenu()
let aboutMenuItem = NSMenuItem(title:"About", action:#selector(StatusBarApp.about(_:)), keyEquivalent:"")
aboutMenuItem.target = self
let quitMenuItem = NSMenuItem(title:"Quit", action:#selector(StatusBarApp.quit(_:)), keyEquivalent:"")
quitMenuItem.target = self
menu.addItem(aboutMenuItem)
menu.addItem(quitMenuItem)
statusItem.menu = menu
}
func about(sender : NSMenuItem) {
print("XXX")
}
func quit(sender : NSMenuItem) {
NSApp.terminate(self)
}
}
NSApplication.sharedApplication()
let statusBarApp = StatusBarApp()
NSApp.delegate = statusBarApp
NSApp.run()
update action
aboutMenuItem.action = Selector("about")
and add
aboutMenuItem.enabled = true
Consider this:
import Cocoa
class StatusBarApp : NSObject {
func buildMenu() {
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
statusItem.title = "StatusBarApp"
let menu = NSMenu()
let aboutMenuItem = NSMenuItem()
aboutMenuItem.title = "About"
aboutMenuItem.target = self
aboutMenuItem.action = #selector(about)
menu.addItem(aboutMenuItem)
statusItem.menu = menu
}
func about() {
print("XXX")
}
}
let app = StatusBarApp()
NSApplication.sharedApplication()
app.buildMenu()
NSApp.run()