SwiftUI: what is the equivalent stuff with viewDidLoad and viewWillDisappear - swiftui

I used to put GCDWebServer's start() and stop() in viewDidLoad and viewWillDisappear.
Now in SwiftUI, what is the equivalent place should I put them to?
I try to put server init() into scene(_ scene: UIScene, willConnectTo, and server deinit() in sceneDidEnterBackground(_ scene:.
After launching the app, server is started successfully and when I push app to background, the server is stopped. That is worked fine. But when app returns to the foreground again, the server doesn't start again.
The Code:
class BrandViewController: UIViewController {
let mockServer = GCDServer()
let tableView = UITableView()
private let products = ProductAPI.loadProducts()
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.searchController = searchController
self.navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Search"
view.backgroundColor = .white
tableView.register(ProductCell.self, forCellReuseIdentifier: "productCell")
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
// Start GCDWebServer
mockServer.initWebServer()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
mockServer.stopWebServer()
}
}

If you destroy your server on sceneDidEnterBackground then the solution will be to move server creation (and, as I assume start) from scene(_ scene: UIScene, willConnectTo as you do now into sceneWillEnterForeground.

Related

Swift 3 Create Reminder EKEventStore

I would like to save reminders to the default reminders location. But when I press my button I get a fatal error: unexpectedly found nil while unwrapping an Optional value... I am pretty new to this and most examples I locate are overly complicated or not in Swift 3.
class ViewController: UIViewController {
var eventStore: EKEventStore?
#IBOutlet weak var reminderText: UITextField!
#IBAction func setReminder(_ sender: Any) {
let reminder = EKReminder(eventStore: self.eventStore!)
reminder.title = "Go to the store and buy milk"
reminder.calendar = (eventStore?.defaultCalendarForNewReminders())!
do {
try eventStore?.save(reminder,
commit: true)
} catch let error {
print("Reminder failed with error \(error.localizedDescription)")
}
}
}
As its a simple piece of code I thought I would post my answer after I figured it out for any future swifters. I always like simple examples.
import UIKit
import EventKit
class ViewController: UIViewController {
var eventStore = EKEventStore()
var calendars:Array<EKCalendar> = []
// Not used at this time
#IBOutlet weak var reminderText: UITextField!
#IBAction func setReminder(_ sender: Any) {
let reminder = EKReminder(eventStore: self.eventStore)
reminder.title = "Go to the store and buy milk"
reminder.calendar = eventStore.defaultCalendarForNewReminders()
do {
try eventStore.save(reminder,
commit: true)
} catch let error {
print("Reminder failed with error \(error.localizedDescription)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// get permission
eventStore.requestAccess(to: EKEntityType.reminder, completion:
{(granted, error) in
if !granted {
print("Access to store not granted")
}
})
// you need calender's permission for the reminders as they live there
calendars = eventStore.calendars(for: EKEntityType.reminder)
for calendar in calendars as [EKCalendar] {
print("Calendar = \(calendar.title)")
}
}
override func viewWillAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
With the #adamprocter sample, we also need to add "NSRemindersUsageDescription" key with your message in info.plist file. I tried adding this as a comment but I am not eligible.

Make Search Bar Become First Responder

I have a UISearchController inside of a UINavigationBar. The user has to tap on a UIBarButtonItem, in which I instantiate a new UIViewController then present it, in order to begin searching.
class ViewController: UIViewController {
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
setupSearchController()
}
func setupSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.showsCancelButton = true
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
definesPresentationContext = true
navigationItem.titleView = searchController.searchBar
}
}
I've done plenty of research before hand, but still can't manage to find a solution...
Help in making the search controller become the first responder would be very much appreciated.
Making the UISearchBar the first responder on the main thread was the solution.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}

transitioningDelegate never called after Segue transition

So I'm trying to implement a custom animation as my app transitions from one View Controller to another, but for some reason the animateTransition function in my custom animation class is never called.
For the record, I'm using Xcode 8 and writing in Swift 3. The problem I'm trying to over come, is that the function is never called - I'll sort out the actual animation in the future, for now its
Here is the code in my CustomPresentAnimationController class, which should handle the transition animation...
import UIKit
class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
let duration = 0.5
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
print("Checking duration")
return duration
}
func animationController(forPresented presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 1")
return self
}
func presentationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 2")
return self
}
func animationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
print("This ran 3")
return self
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
print("It's working!")
guard let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from) else {
return
}
guard let toView = transitionContext.view(forKey: UITransitionContextViewKey.to) else {
return
}
let container = transitionContext.containerView
let screenOffDown = CGAffineTransform(translationX: 0, y: -container.frame.height)
let screenOffUp = CGAffineTransform(translationX: 0, y: container.frame.height)
container.addSubview(fromView)
container.addSubview(toView)
toView.transform = screenOffUp
UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: [], animations: {
fromView.transform = screenOffDown
fromView.alpha = 0.5
toView.transform = CGAffineTransform.identity
toView.alpha = 1
}) { (success) in
transitionContext.completeTransition(success)
}
}
}
Here is the code for my ViewController (which both of my View Controllers reference)...
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate {
override func viewDidLoad() {
if transitioningDelegate != nil {
print("Should do something...")
print(transitioningDelegate)
} else {
print("Transitioing Delegate set to nil")
}
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationController?.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
let customPresentAnimationController = CustomPresentAnimationController()
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("doing our custom transition")
print(segue.destination)
let destination = segue.destination
destination.transitioningDelegate = customPresentAnimationController
}
}
When I run the code, and click on the button I provided, which links to my seance View Controller, and is set to 'Present Modally', the view changes with the standard transition (slides up from the bottom) - and the following is printed out to Xcode:
Transitioing Delegate set to nil
doing our custom transition
<moduleView.ViewController: 0x7fe427f09a40>
Should do something...
Optional(<moduleView.CustomPresentAnimationController: 0x60800002e980>)
Obviously the first line is just as the first view loads, all the rest shows that my transitionDelegate is set on the Segue destination, and is indeed loaded in as the second view loads, and that the transitionDelegate is set to CustomPresentAnimationController... yet none of the functions in that class are ever called as it never prints anything out from those functions.
Any help appreciated!
Ensure the method signature for implementing the delegate matches the updated Swift 3 syntax.

Local Notificaton not working in simulator iOS10.0

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
askForPermission()
}
#IBAction func addLocalNotification(_ sender: AnyObject) {
addLocalNotification()
}
func addLocalNotification() {
let content = UNMutableNotificationContent()
content.title = "iOS10.0"
content.body = "Hello Buddy"
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "FiveSecond", content: content, trigger: trigger)
// Schedule the notification.
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error)
}
print("should have been added")
}
func askForPermission() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge]) { (granted, error) in
}
}
You have to implement a delegate to UNUserNotificationCenter to tell the system you want to display the notification while the app is running. See the sample here: https://github.com/jerbeers/DemoLocalNotification

Update NSArrayController correctly

I'm trying to populate NSTableView using NSArrayController, however can't get it to work. Here is my code:
class AppDelegate: NSObject, NSApplicationDelegate {
private let _spadList: SpadList
var spadList : SpadList {
get { return _spadList }
}
override init() {
_spadList = SpadList()
super.init()
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
createInitialData()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func createInitialData() {
_spadList.chain = "CHAIN"
_spadList.service = "Service"
_spadList.dateString = "2016-12-12"
let firstEquity = Equity()
let anotherEquity = Equity()
firstEquity.name = "Apple"
firstEquity.tradePrice = 12.3
anotherEquity.name = "ORACLE"
anotherEquity.tradePrice = 45.7
_spadList.addEquity(equity: firstEquity)
_spadList.addEquity(equity: anotherEquity)
}
}
And this is ViewController:
class ViewController: NSViewController {
let appDelegate = NSApplication.shared().delegate as! AppDelegate
#IBOutlet weak var tableView: NSTableView!
func equities() -> [Equity]{
return appDelegate.spadList.equities
}
}
Content Array of the NSArrayController is bound to: ViewController.equities
The issue is that my manually created data are not populating itself into my tableView. If I move createInitialData() to ViewController class, they are correctly displayed.
What am I doing wrong?