Creating an outlet for a NSProgressIndicator inside a NSToolbar - macos

I have this OSX storyboard-based application that starts with a NSSplitViewController like this:
This splitViewController has two viewControllers: master and detail.
Inside the window I have a NSToolbar. I dragged a NSProgressIndicator to that toolbar and Xcode embedded it inside a NSToolbarItem.
Now I need to create an outlet (not an action as explained on other stackoverflow questions) from the NSProgressIndicator to some class. First question is which one?
Xcode will not let I create an outlet. I have tried these options:
dragged from the ToolbarItem to masterController class file, detailController class file and to NSSplitViewController class.
dragged from the ToolbarItem to the delegate class.
dragged from the NSProgressIndicator to masterController class file, detailController class file and to NSSplitViewController class.
dragged from the NSProgressIndicator to the delegate class.
dragged from both the NSToolbarItem and from the NSProgressIndicator to the Window Controller First Responder.
In all cases dragging does not make a window appear to allow me to create the outlet.
For heavens sake, how do I create an outlet like that? To which class I drag it and how do I do that?

I'll assume your setup is more like this image:
Your Window scene is backed, by default, by an NSWindowController, to which you cannot add new outlets. You need to create a subclass of that, associate it with your Window and then you should be able to create outlets in that.
File > New File > Cocoa Class
Specify a name like "SpaceDogsWindowController", as a subclass of NSWindowController.
Then use select the window controller icon (blue circle) and select the Identity Inspector in Xcode. (CMD+ALT+3). Specify the name of your new class in the "Class" field.
Then try to hookup an outlet:
1) Show the Assistant Editor
2) Use the Jump Bar to ensure your custom class is visible (It's at the top of the assistant editor pane, it should say Automatic and you can tap that to then select your new class; If it says 'Manual', change it to Automatic).
3) If your are control-dragging and it's still not offering to make a connection, try dragging from the document outline (also shown in the screen shot).
You could then edit that progress indicator from other view controllers, which are descendants of that window's view hierarchy, using code like this:
if let windowController = self.view.window?.windowController() as? CustomWindowController {
windowController.progressIndicator.doubleValue = 0.4
}
or, in Objective-C, something like this:
CustomWindowController *myWindowControllerSubclass = self.view.window.windowController;
windowController.progressIndicator.doubleValue = 0.4;
Hope that helps.

Related

Xcode Outlet/Action connection UITextField

I'm trying to add my text field as an Outlet in my ViewController.swift, but when I drag the text field from the Main.storyboard to the ViewController it only shows as action and I cannot change it to Outlet.
I had this problem too! I fixed it by clicking on the top bar of my UIViewController (in the storyboard looking window), then selecting the Identity Inspector on the right and in the top where it says Custom Class in bold there is a field called Class which I set to the viewcontroller file I was trying to control-drag the UITextField to. Once the Class was set to the right name I was able to control-drag for an outlet. I hope this helps.

Xcode add collection view cell to collection view on interface builder

I am relatively new to using XCode interface builder.
When trying to drag a collection view cell onto an empty collection view, the interface builder refuses to do so.
Please have a look at attached screenshot:
Am I doing anything wrong?
Note that I can do the same on a storyboard but not on a normal xib file.
You can only add a UICollectionViewCell inside a UICollectionView when working on a Storyboard file. For sure, you must be using a single nib file and that's why it isn't working.
If you wanna use a custom UICollectionViewCell, then you must create a subclass of UICollectionViewCell. When subclassing UICollectionViewCell don't forget to check the box that says "Also create XIB file" beneath the expandable menu of "Subclass of". Now, try to drag a UICollecionViewCell onto the canvas and custom it the way you want.
Another posibility would be using a Storyboard file. Try setting your UICollectionView inside a scene in the storyboard and then drag a UICollectionViewCell inside it. When dragged, create a UICollectionViewCell subclass and assign it to the UICollectionViewCell you dragged previously inside your CollectionView in the Identity inspector.
In either case, don't forget to set the reuse identifier of your UICollectionViewCell in the Attributes inspector :)
Here is a code sample from Apple of how to create a UICollectionView with a custom UICollectionViewCell using a storyboard.
https://developer.apple.com/library/ios/samplecode/CollectionView-Simple/Introduction/Intro.html#//apple_ref/doc/uid/DTS40012860
Hope this helps :-)

How to use NSToolBar in Xcode 6 and Storyboard?

I've been trying to build on a Cocoa app that uses Swift and Storyboard in Xcode 6, but how can I use NSToolbar there?
In Xcode 5 and xib, you can add NSToolbar from within Object Library to any .xib files and then click on the added toolbar to expand it and drag and drop a connection from any items there to a AppDelegate.h file. In this way you can create a IBAction or IBOutlet connection. I confirmed that this can also be done if you use Swift and non-storyboard in Xcode 6. However, it looks like this is not the case in Xcode 6 and Storyboard environment.
I first created a project that uses Storyboard in Xcode 6, but then, I wasn't able to add a NSToolbar from within Object Library to a View Controller in Storyboard. So I added it to Window Controller's Window object in Storyboard. However, in this way I cannot create those connections from any items in the expanded toolbar to either AppDelegate.swift or ViewController.swift.
So my question is:
Is it feasible to create a storyboard app that uses NSToolbar?
If it is feasible, is the addition of NSToolbar to the Window Controller the proper way to use NSToolBar in Storyboard?
Finally, how can I create #IBOutlet and #IBAction connections there?
UPDATE
I found that the accepted answer by #GeorgeVillasboas only works for #IBAction. I am still looking for how to create an #IBOutlet connection...
I had this very same problem.
The solution works for both Objective-C and Swift projects.
Working with Storyboards on OSX, it creates an instance of NSWindow and segues to another NSViewController as its Window Content Segue, as you described.
On your ViewController, create a standard IBAction to receive the action when the toolbar is clicked. To wire it up with the NSToolbar, just control-drag (or leftClick-drag) from your NSToolbarItem to the FirstResponder object, as shown on the picture below.
This will open a HUGE list of available connections. Your IBAction will be on that list.
Just selected it and you're good to go.
Hope this helps!
Here's an answer that doesn't rely on run-time hook-ups - #cdalvaro's answer gets most of the way there for some applications, but isn't full, and it requires the ViewController to know about the artificial NSWindowController, which doesn't feel right.
Like #cdalvaro, the first step is to build your own subclass of NSWindowController, and to set the Storyboard WC to that class. You can then create all of your connections to and from the NSToolbar (both #IBOutlets & #IBActions) in the new WindowController. So far so good.
The last step, which I haven't seen anywhere else, is how to refer to the ViewController in the WindowController - you can't create an #IBOutlet to it - for the same reasons that we got here in the first place - you can't create references across scenes in the Storyboard. However, the WindowController must have a reference to the ViewController, and it does... self.window!.contentViewController! as! ViewController
Here's a complete WindowController with a checkbox that sets values in the ViewController, without the ViewController having to know anything...
class MyWindowController: NSWindowController {
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
#IBOutlet weak var aSwitch: NSButton!
#IBAction func toolbarActionA(sender: AnyObject) {
println("toolbarActionA")
self.viewController.a = !self.viewController.a
self.aSwitch.state = self.viewController.a ? NSOnState : NSOffState
}
}
This helped me for the IBOutlet solution you are looking for:
https://stackoverflow.com/a/27555237/3398062
Update (explanation)
I discovered this thread because I was trying to create a Circular Progress Indicator inside the toolbar and I didn't know how to animate it from the ViewController since the IBOutlet was declared inside a custom WindowController.
Finally, I found the post that I have added above which describes how to access to IBOutlets from other classes.
In essence what I have done is the following:
Create a custom NSWindowController subclass (CustomWindowController) for the Window Controller so I can add the IBOutlet for the ProgressIndicator:
Code Example:
#interface CustomWindowController : NSWindowController
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#end
Then in the ViewController class, in the method I want to use to update the state of the Progress Indicator, I create and object of the custom Window Controller.
Code Example:
CustomWindowController *customWindowController = self.view.window.windowController;`
Finally, to change the state of the Progress Indicator there is only to call the method from the created custom object.
Code Example:
[customWindowController.progressIndicator startAnimation:sender];
or
[customWindowController.progressIndicator stopAnimation:sender];
This video helped me how to create a toolbar without writing a single line of code: https://www.youtube.com/watch?v=XSQocHG3IjA
You can add the 'Window Controller' item from the Object Library (if you don't have one), connect to a View Controller (where you want your toolbar to display) and follow the video! For custom Toolbar buttons add 'Image Button' item to the Toolbar just by dragging from the Object Library. Then you can pick an image for a button, set the size and so on...
Here is a general solution for the outlets and actions. it allows you to preform all the the same functions as an iboutlet would for a tool bar item and also allows you to set the button to a function instead of creating an ibaction. hope it helps :P
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
Here is a link to my question attempting to get a cleaner answer
http://www.stackoverflow.com/questions/27371439/use-nstoolbar-outlet-xcode-6-and-storyboard/27374449
but it looks like from the answers i have gotten so far this is the best option.
The same problem of IBOutlets also applies to KVO. One of the features of the NSSplitViewController is the canCollapse property for each split view item which supports KVO, but this is unusable in IB just like IBOutlets.
The only workaround I can see is to add a NSObjectController to each scene and when the scene loads, set the object controller's object to the object in the other scene (already loaded) that you want to reference.

Finding File Owner in Xcode 4.2

Please glance at the image below and help me find a File Owner for the class.
Generally i would connect my UILabel to it, but, alas, i can't find it.
Question: What should i connect my Label to?
Storyboard:
Meanwhile class is set up as
As storyboards don't have an owner, you can use the View Controller instead.
Ctrl click (or right click) the label, drag the blue line to connect up with the orange View Controller.
Right click the Label and connect to the View controller scene
You have put your finger on a key difference between storyboards and nibs: when a nib is loaded, an owner instance is specified, but a storyboard is not loaded with an owner, so there is no file's owner in a storyboard. Your ViewController instance is created by the storyboard and is proxied in the scene (listed as View Controller), so you can draw a connection between that and an interface item. But if you want to form a connection with an already-existing instance not represented in the storyboard, you'll have to identify that instance in some other way (perhaps by a tag) and find it and runtime and form the connection in code after the storyboard loads.
For example, in this code, I manually load a storyboard (to use its initial scene in a popover) and then form connections from some bar button items within it:
UINavigationController* nav =
(UINavigationController*)[[UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil]
instantiateInitialViewController];
// there is no file's owner...
// so we can't just draw the connection from button items to ourself,
// because we are not proxied in the storyboard
// so, locate the button items in some other way and do it in code
UIViewController* root = [nav.viewControllers objectAtIndex: 0];
[root.navigationItem.leftBarButtonItem setTarget:self];
[root.navigationItem.leftBarButtonItem setAction:#selector(save:)];
[root.navigationItem.rightBarButtonItem setTarget:self];
[root.navigationItem.rightBarButtonItem setAction:#selector(cancel:)];
In some cases, there's a trick you can use to inject an arbitrary existing instance into a scene so that a connection to it will work: make that instance the first responder. There is a first responder proxy in every scene, so this can give you something to connect to by drawing within the storyboard. So, this code could work instead of the above:
[self becomeFirstResponder];
UINavigationController* nav =
(UINavigationController*)[[UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil]
instantiateInitialViewController];
(And the button action connections have been drawn in the scene from each button to the first responder proxy object.)
Menu: Navigate - Reveal in Project Navigator
In the Project Navigator, Click on the "Main Storyboard"
Menu: View - Show Assistant Editor
You should have the Storyboard on the left with your label, and the view controler.h text on the right.
Click on your label, hold down the control button, and drag a blue line to the View Controler.h source code on the right. Type in a reference name (for example myLabel), and click connect.
Automagically you will see something like this generated:
#property (weak,nonatomic) IBOutlet UILabel *myLabel;
Inside the View Controler.m, you will see something like this generated:
#synthesize *myLabel;
Inside your IBAction events, you can set the label:
myLabel.text =

Code Pattern: Loading TabBarController objects directly from independent .xib file (instead of from MainWindow.xib)

I've looked around online, and haven't been able to find an acceptable solution to this problem...
I'm looking for a simple code pattern:
Load a TabBarController object (with associated subview controllers) from a separate .xib file, instead of including and loading automatically from a default MainWindow.xib.
In XCode terms, starting from a new iPad/iPhone project as a "Tab Bar Application", the goal is to solve the following:
Create the project
Move: TabBarController, TabBar, FirstViewController, and SelectedSecondViewController from MainWindow.xib, into a new "TabBarController.xib" file
After moving, MainWindow.xib should only contain: File's Owner, First Responder, App Delegate, Window
In TabBarController.xib, File's Owner and First Responder are set to: UIApplication and UIResponder, respectively.
Change "didFinishLaunchingWithOptions" in the main application delegate to the following:
REMOVE:
[self.window addSubview:tabBarController.view];
ADD:
UITabBarController *uiTab = [[UITabBarController alloc] initWithNibName:#"TabBarController" bundle:nil];
[self.window addSubview:uiTab.view];
With these changes, the application builds and runs, but when the TabBarController loads the tab bar is "empty" -- there don't appear to be any contents in the controller.
In looking in the debugger, either the "init" isn't initializing from the data correctly, or something in the .xib file is not set correctly.
What is the correct solution to this? I realize there are other ways of doing this, and yes, I have them working in other applications.
What I'm looking for however, is a specific solution using the default project, that can be used as a general pattern for setting up iOS code.
Thanks in advance for any help
js
I think i know what you are looking for because i want the same thing.
Create New Empty xib file at interface builder.
Add to the xib TabBarController from the library.
Edit whatever you need on this tab bar controller on the xib.
Of course, save...
Determine from which view controller do want to create that xib with tab bar controller. In other words, who is the view controller that will cause this tab bar controller to appear.
Let's call that view controller ParentViewController
In that view controller, create an IBOutlet to a TabBarController.
Back to the xib, make the identity of the File's Owner to the ParentViewController and of course dont forget to hook up the outlet of the tab bar controller in the file's owner to the tab bar controller in the xib.
save the xib and you are ready to go.
When you want to present that tab bar, just decide which way you want to do it: Modally,Popup or something else (Not inside a navigation controller because Apple dont allow tab bar controllers to be inside navigation controllers).
When you decide, just present your tab bar controller outlet the way to present any other view controller. for example:
[self presentModalViewController:self.myTabBarController animated:YES];
Assuming you start with the "Tab Bar Application" template and move the UITabBarController and associated view controllers to a new nib as you described...
In your new nib, File's Owner should be set to your AppDelegate class. Then connect the outlet "tabBarController" of File's Owner to the UITabBarController.
Then in your -[application:didFinishLaunchingWithOptions:], do not remove this line:
[self.window addSubview:tabBarController.view];
Instead, load the new nib right before that with your app delegate as the owner:
[[NSBundle mainBundle] loadNibNamed:#"TabBarController" owner:self options:nil];
That will set your tabBarController property (since you made that connection in the nib) and then you can proceed as normal. What you were doing was actually creating a whole new UITabBarController, and not loading the one from the nib at all. (well, ok you were loading it for a brief moment, but then not doing anything useful with it)
Hope that helps.

Resources