Xcode's IB cannot show up my custom view? - xcode6

Xcode's IB cannot show up my custom view?
Recently, i updated my Xcode to Version 6.4 (6E35b) and encounter an IB problem.
Before i update my xcode, all my custom view (extend uiview) can show up in IB.
required init(coder aDecoder: NSCoder) {
// 1. setup any properties here
// 2. call super.init(coder:)
super.init(coder: aDecoder)
// 3. Setup view from .xib file
xibSetup()
}
Currently, I cannot see my custom view in IB. But it can work well during the run time.
How can I make them show up in my IB?

Finally, i got a solution.
It not caused by my update of Xcode.
It caused by my closed the "Auto-Refresh" feature within IB.
So the solution is: Xcode -> Editor -> Refresh All Views
Then i think you will see all your custom view within IB.

Related

How can I delegate one NSViewController from another NSViewController in ObjC on Mac? [duplicate]

Hi I've seen this question asked a few times already but with no definite answer yet so I created it for xcode 7 and swift2 (which may have changed things a bit anyway).
I created a project using Xcode 7 and Cocoa OSX Story boards + swift2, so my project started with a NSWindowController that Connects to a NSViewController (as expected!). I added a NSToolbar to my window controller and added a NSButton to the toolbar. I changed my NSViewController to be one of the new NSSplitViewController that links to three NSViewControllers and displays their views horizontally - with vertical dividers - (similar to the layout you see in the photo app or pages in Yosemite +). My final goal will be that the button in My toolbar shows and hides the first split.
It is my understanding is, and I would expect that to achieve this I should create an action in the NSSplitViewController that changes the auto layout constrains more or less in the way they are working it out here: How to do collapse and expand view in mac application?.
And then somehow link this action to the NSButton that is in the Toolbar... which happens to be in the NSWindowController (far up and isolated in the hierarchy)...
I have already gone through other questions about NSToolbar and storyboards and failed to accomplish my goal:
The YouTube video: Cocoa Programming L17 - NSToolbar which is the closest I found to solve the problem, but his method does not work for storyboards, only creating your own xib file.
In this question: How to use NSToolBar in Xcode 6 and Storyboard? One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...). A second person suggested to create a view controller variable in the NSWindowController and manipulate its properties from there... but again, a bit dodgy too.
One latest comment I saw in that question which seems the best way to tackle the problem (but still not as good as I guess it could be) is to add a NSObjectController to the dock of each scene and when the scene loads, set the values of the objects to the other secene's controller. Is this really the best way to go ahead? If so, how could I achieve this one?
Apple did mention (again) in WWDC15 that they created storyboards for osx and the split-view controller that owns view-controllers so that you can move your logic and work to the specific view-controller, so I would be expecting to do everything from inside my split-view controller as this is the target that needs to change.
Does anyone know how to achieve this from the view controller itself? I really haven't been able to find a way to connect my ToolBarItem to it.
OK, I've created this question quite a few days ago and no answer so far so I've answer with what I recently did to overcome the problem.
After I created my Xcode project I did this:
Created a subclass MySplitViewController for the NSSplitViewController
Added an IBOutlet for each NSSplitViewItem. For example:
#IBOutlet weak var mySplitViewItem: NSSplitViewItem!
Created a subclass WindowController for the NSWindowController
Added an IBAction in the WindowController class that links to the NSToolbarItem (my button)
Added a property that gets the Window Controller's content as MySplitViewController
var mySplitViewController: MySplitViewController {
return self.window?.contentViewController as! MySplitViewController
}
Now I can access the split view controller's property from the Window Controller in the action I created:
mySplitViewController. mySplitViewItem.collapsed = true
I created some sample code that does this (but using a view controller and changing the text for a label here, just in case someone wants to see a working project with this behaviour. And a blog post about it too :)
One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...).
I think this first responder method is actually the proper way.
As an example:
Add something similar to the following, in whichever view controller makes sense.
#IBAction func doSomething(_ sender: AnyObject?) {
print("Do something.")
}
This will magically show up in the first responder:
In your storyboard, right-click the orange "first responder" icon above your window controller, and you should see doSomething in the very long list. You just need to connect that up to your toolbar button.
In the following screen capture, you can see my "Toggle Sidebar" button is connected to the toggleSidebar action in my first responder.
I didn't even have to write this method — it's provided by NSSplitViewController:
#IBAction open func toggleSidebar(_ sender: Any?)
So, I was working this same issue and finding no solution as you experienced. I read your post and was trying to figure how I would implement your solution when it occurred to me to use a notification. In about 30 seconds, I had a perfectly fine working solution:
In your windowController add an IBAction to post a notification like so
-(IBAction)toggleMasterViewClicked:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:nil];
}
Hook up that action to your NSToolbarItem, then in the viewController add self as an observer for that notification like so
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(toggleMasterView:) name:#"TestNotification" object:nil];
In your case, selector would be updateMyLabelText
I don't really see any downside here. No reference to other objects needed, no dependancies. Works flawlessly for me
While connectiong IBActions works by using either the First Responder or by adding an "Object" to the scene, then changing its class to the window's view controller class, this doesn't help with IBOutlets and delegates that you'd like to point to the view controller.
Here's a work-around for that:
Add the Toolbar to the View Controller, not to its Window. That way, you can make all the IBOutlet connections in the View Controller Scene easily. I've done that for years and found no issues with it, even when using Tabs.
You'll have to assign the window's toolbar in code, then. E.g. like this:
#interface ViewController ()
#property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
#end
- (void)viewWillAppear {
[super viewWillAppear];
self.view.window.toolbar = self.toolbar;
}

Youtube like view in landscape mode using size classes in Ipad

I need to change my existent view in landscape to something similar like Youtube does in landscape .. Currently i'm using size classes and storyboard to achieve it but the problem is my layout should change considerably in landscape compared to the portrait and since the size classes for both ipad portrait and landscape is same ,should i use a separate view controller for the landscape version .. My current portrait view is also slightly complex which has child view controllers embedded in it .. What is the best approach to follow for the seamless transition from ipad portrait to landscape ..Do you think youtube is using different viewcontrollers/xib's to achieve it .. Another problem is this code has been written by some other company and the instructions given to me is to not change the existent code much .. I dont want to fiddle with it much ..
PFA for the images of how the current version looks and how it should look like landscape..
Current version
Proposed version
Edit 1: I have already implemented viewWillTransitionToSize in my view controller .. My question is, should i be using two different xib's or can i use a different view controller altogether for landscape version ..What are the pros and cons of it ? As evident from the below pics , i need to do quite a few changes to my landscape version ..
reduce the size of video , hide the segmented control and add two tableviews to the side..
You should implement the UIContentContainer protocol method viewWillTransitionToSize and check the width and/or height of size with your view controller's view's frame and act accordingly.
In Swift:
override func viewWillTransitionToSize(size: CGSize,
withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if traitCollection.verticalSizeClass == .Regular && traitCollection.horizontalSizeClass == .Regular {
if size.width > self.view.frame.size.width {
// Moving to landscape
} else {
// Moving to portrait
}
}
}
Discussion
UIKit calls this method before changing the size of a
presented view controller’s view. You can override this method in your
own objects and use it to perform additional tasks related to the size
change. For example, a container view controller might use this method
to override the traits of its embedded child view controllers. Use the
provided coordinator object to animate any changes you make.
If you override this method in your custom view controllers, always
call super at some point in your implementation so that UIKit can
forward the size change message appropriately. View controllers
forward the size change message to their views and child view
controllers. Presentation controllers forward the size change to their
presented view controller.

UICollectionView items not showing after migration to Swift 2

After migrating my Xcode 6 project to Xcode 7, only the first UICollectionView in my app renders properly.
When I switch tabs the CollectionView doesn't render properly.
The app worked fine in iOS 8.
Example:
Here is a CollectionView header in the Storyboard.
When I run my app, I am getting a blank view.
Interestingly enough, when I use the View Hierarchy debugger, it
shows that the element in fact does exist.
So it looks like ios9 has a bug when rendering custom cells.
I would suggest creating your custom cells in xibs and then loading them from there.
Make sure to include this in viewDidLoad:
self.collectionView.registerNib(UINib(nibName: "SongCell", bundle: NSBundle.mainBundle()), forCellWithReuseIdentifier: "SongCell")
self.collectionView.registerNib(UINib(nibName: "SongHeader", bundle: NSBundle.mainBundle()), forCellWithReuseIdentifier: "SongHeader")
Make sure you add this line in viewDidLoad of your collectionView controller
self.collectionView!.registerClass(YourCustomMemeClass.self, forCellWithReuseIdentifier: "reuseIdentifier")

Forwarding drag & drop event to parent view

I have an application where I have one custom view which is derived from NSView.
Within this view, there are several custom subviews, which are also derived from NSView.
I want to implement a drag and drop behavior which allows URLs to be dropped onto the views. Everything is already working for the main view.
So, actually I would have to implement dragging behavior handlers on the child-views and the parent-view class.
The thing is, that I don't want to copy the complete handling code to all the child-views to make them also accept drag events. So I thought that it would be the best way to just let them forward all drag events to the parent view.
Is this possible somehow?? Not sure if I can somehow set this up with the responder-chain maybe?
Any tips are highly appreciated!!
Thanks in advance.
I faced a similar issue where I wanted anything dropped in a view, or any of it's subviews to be processed by the view, but the calls never got there.
After some research I found this answer to be the most helpful: https://stackoverflow.com/a/7389711/327471
Essentially if a view is not registered to receive any drag events it should pass that information up to it's parent view automatically. So in my case I ended up with something like this:
NSArray *subviews = [self.view subviews];
for (NSView *aSubview in subviews) {
[aSubview unregisterDraggedTypes];
}
Of course you can be more precise than that, and make sure to only check subclasses of a certain type or whatever parameters you want. But ultimately the key was unregistering the problem subview from it's dragged types.
I hope this helps.
If the subviews are used for display only and don't require any user interaction, you can override -hitTest: in the parent view like so:
- (NSView *)hitTest:(NSPoint)aPoint
{
NSView* hitView = [super hitTest:aPoint];
if(hitView)
return self;
return nil;
}
This makes the parent view receive all mouse events.
Still works XCode 10.1. Swift 4.2. under 10.14.4 Beta (18E184e).
// MARK: - ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.view.subviews.forEach { $0.unregisterDraggedTypes() }
}
There's probably a better way, but you could put your dragging protocol implementation in a category, rather than in the view directly, and include that category in each of the views.

iOS 5 storyboard, programmatically determine path

I'm having trouble to achieve the following using a storyboard:
When setup is not done:
run app -> show settings view controller -> show main navigation controller
When setup is done:
run app -> show main navigation controller
So basically, I want the app to programmatically start with the settings view in certain cases, and otherwise skip right ahead to the main navigation controller.
I did manage to show the settings view with a modal style segue from the main navigation controller, but I don't know how to display it before the main navigation controller is displayed. Any ideas?
By default, the initial view controller from your main storyboard is instantiated and displayed automatically when your app starts up. To prevent this happening you need to remove the UIMainStoryboardFile setting from your info.plist file.
With no default view controller, you are now free to create one programmatically at app startup. See the UIStoryboard documentation. Use +storyboardWithName:bundle: to load the storyboard and then use –instantiateViewControllerWithIdentifier: to create the correct view controller. You will also need to create a main UIWindow and add the view controller's view to it just like you used to do with .nib based UI. Note that without the UIMainStoryboardFile setting a main window is not created for you - read the explanation.
I managed to do it a bit different:
Use a UINavigationController as the initial view controller.
Create a root view controller that will manage the decision of what to load.
Create a Storyboard Segues from the root view controller to the main view and to settings view, and give the segues proper identifiers.
Call the performSegueWithIdentifier with the proper identifier from your root view controller.
Just another solution, hope this helps.
I did something similar to amoshaviv, his advice is sound. I did it slightly different though, and I'll give some more info.
I created a custom MyInitialViewController class, derived from UIViewController, and made this the initial view controller.
In the storyboard file, I created modal segues with appropriate names to all (in my case three) possible 'real' first view controllers.
In the MyInitialViewController class, I implemented the
- (void)viewDidAppear:(BOOL)animated;
method, to first perform the check which view to switch to, and then do the correct
[self performSegueWithIdentifier:#"NameOfSegue" sender:self];
Effectively, this makes the MyInitialViewController nothing more than a switch performed when it's brought into view. I first tried doing this when loaded because I don't care for actually seeing this view, but that did not work, while viewDidAppear does.
To make this visually smooth, I tried the following. In the properties of the segues, I disabled animation. The view I left empty, and I gave it a background color matching to that of the startup image.