Issue in IBOutlet reference in Custom delegate method in swift - swift

There is one controller and we are using a segmented controller on it. There is also a right navigation bar button and now we want to show a popupView on the segmented controller on click.
So I made a custom delegate for that bar button action.
When the button is clicked then the custom delegate method fires and it is working fine.
Now if I want to access the IBOutlet of popup view in that delegate action then it shows "Nil"
Main controller containing segmented controlle, container view and right navigation bar button:
// this is a protocol for button click
#objc protocol ClassList {
func classData(id:NSArray,className:NSArray)
}
// this is button action method of right navigation bar button
#IBAction func classFilter(sender: AnyObject) {
//dispatch_async(dispatch_get_main_queue()) {
self.delegate?.classData(self.classID as NSArray, className: self.dataPicker as NSArray)
//}
}
Segmented controller:
func classData(id: NSArray, className: NSArray) {
// method fire correctly
self.pickerView.hidden = false // crash app because pickerView reference nil
}

Related

Dismiss delegate for UIMenuElement Swift

I have a UIMenu on my app and I want to detect when a user taps outside(dismiss) the UIMenu. But it seems like Apple does not support any delegates by default for this action.
Because when a user taps outside I want to change the image of the button.
Sample Image
One rather hacky way I found, is to subclass UIButton and override contextMenuInteractionWillEndFor.
class MyButton: UIButton {
override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
super.contextMenuInteraction(interaction, willEndFor: configuration, animator: animator)
print("ending!")
}
}
contextMenuInteractionWillEndFor is the delegate method that is called when you dismiss a UIMenu, but if you are setting the button's menu property, the button itself will become the delegate of the UIContextMenuInteraction, and you can't set it to something else, which is why you have to subclass UIButton.
Compare this to when you are adding a context menu using addInteraction, where you have control over the UIContextMenuInteractionDelegate.

Tab Bar Items change colors

I have tabBar with 5 items. My app start on first item and all has white color. When I tap on another item nothing change - this is clear, but is possible that when I tap on second item all the items change color to black or when I tap on third item their color change back to white?
Yes, to achieve it you have to options depending on your setup, in both cases you have to implement the following method func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem):
If you are using a ViewController, it will have to implement the UITabBarController and UITabBarControllerDelegate. You will have to set the delegate property to self, you have to do it in the viewDidLoad method:
self.delegate = self
If you are using a Tab Bar Controller Scene in your Storybard), create an instance of a UITabBarController class, in my example TabViewController, and set it as a custom class in your Tab View Controller.
Next, in both cases you will have to implement the following method:
override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem)
self.tabBar.tintColor = UIColor.red
}

How to reference a View from within a Window Controller?

I'm having a Window Controller with a toolbar. I also have a View Controller containing some views. How do I reference a view from the View Controller within my Window Controller? I'm still learning macOS development and I'm missing the bigger picture how code is structured and classes are meant to interact.
My concrete problem right now is this: Using XCode 9.4.1 I have a window with a toolbar and a button in it. That's how my WindowsController.swift looks like:
import Cocoa
class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
window?.titleVisibility = .hidden
}
#IBAction func startExport(_ sender: NSButton) {
print("Start Export")
}
}
In the ViewControllerScene there's a WKWebView that's loading a web page. When the button in the toolbar is pressed, I want to call that Web Views takeSnapshot method. So I need a reference in WindowsController.swift to that Web View, but control-dragging the Web View from the storyboard to WindowsController.swift in the assistant editor doesn't let me create that outlet.
This:
let vc = contentViewController as? ViewController
will take you to your view controller.

macOS application like Photos.app on macOS

I'm trying to create a macOS app like Photos.app. The NSWindowController has a toolbar with a segmented control. When you tap on the segmented control, it changes out the the NSViewController within the NSWindowController.
What I have so far is an NSWindowController with an NSViewController. I have subclassed NSWindowController where I have the method that gets called whenever the user taps on the segmented control.
Essentially, whatever segment is clicked, it will instantiate the view controller that is needed and set it to the NSWindowController's contentViewController property.
Is this the correct way of doing it?
Also, the NSWindowController, I am thinking, should have properties for each of the NSViewControllers it can switch to that get lazy loaded (loaded when the user taps them and they get held around to be re-used to prevent re-initializing).
Code:
import Cocoa
class MainWindowController: NSWindowController
{
var secondaryViewController:NSViewController?
override func windowDidLoad()
{
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
#IBAction func segmentedControlDidChange(_ sender: NSSegmentedControl)
{
print("Index: \(sender.selectedSegment)")
if sender.selectedSegment == 3 {
if secondaryViewController == nil {
let viewController = storyboard?.instantiateController(withIdentifier: "SecondaryViewController") as! NSViewController
secondaryViewController = viewController
}
self.window?.contentViewController = self.secondaryViewController
}
}
}
I'm new to macOS development, however, I've been doing iOS for quite some time. If there is a better way, I'd like to know about it. Thanks!!!
to move the tab/segmented-control to the titlebar, you need:
add toolbar to window, and add the controls to the toolbar,
hide title:
class TopLevelWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
if let window = window {
// reminder like style
// window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
// window.styleMask.insert(.fullSizeContentView)
}
}
}
now, toolbar will be merged into the top bar position.

tvOS - Detect when TVML is dismissed from my UIViewController

I have a view controller for my app that calls another view controller modally to cover the screen with a blur effect. Inside this other view controller, I'm displaying a TVApplicationController to display TVML content with transparent background on top of this blurred view.
let appControllerContext = TVApplicationControllerContext()
guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
fatalError("unable to create NSURL")
}
appControllerContext.javaScriptApplicationURL = javaScriptURL
appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL
appController = TVApplicationController(context: appControllerContext, window: nil, delegate: self)
appController?.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
self.presentViewController((appController?.navigationController)!, animated: true, completion: nil)
What I want to do is, when I press the MENU button, to make the TVML content go away and to dismiss my modal blur view controller. The problem is that I'm not being able to detect the "dismissal" of the TVML content so I can close my modal view controller.
I tried to use the TVApplicationControllerDelegate to receive the messages that might come while using it but nothing helped.
I just found a workaround for this. I created a small class like this:
import UIKit
class HiddenView: UIView {
override func canBecomeFocused() -> Bool {
return true;
}
}
Then, what I did is to create an instance of this HiddenView on the ViewDidLoad of the blurred view controller and add it to the view controllers's view.
let hiddenView = HiddenView(frame: CGRectMake(0,0,10,10))
self.view.addSubview(hiddenView)
// it won't appear on the screen since it has no color/text/etc
Now, when I press the MENU button on the remote, when the TVML content is dismissed, the delegate method didUpdateFocusInContext on my blurred modal view controller is called, so I can dismiss it like this:
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
self.dismissViewControllerAnimated(true, completion: nil)
}
If anyone knows a better way to handle this than having to do this workaround, it would be nice to know.