NSStoryboardSegue示例代码(Yosemite故事板) [英] NSStoryboardSegue sample code (Yosemite Storyboard)

查看:113
本文介绍了NSStoryboardSegue示例代码(Yosemite故事板)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

OS X Yosemite引入了 NSStoryboardSegue

OS X Yosemite introduced NSStoryboardSegue

"A故事板segue指定了故事板中两个场景之间的过渡或封闭关系…"

更新:

•如果我尝试在带有优胜美地的情节提要中使用NSStoryboardSegue子类,则它会因SIGABRT而崩溃.

• If I attempt to use a NSStoryboardSegue subclass in a Storyboard with Yosemite., it crashes with SIGABRT.

•如果我忽略了segues,并使用指定的自定义动画器手动呈现视图控制器以进行呈现和消除,则

• If I ignore segues, and manually present a view controller using a specified, custom animator for presentation and dismissal,

func presentViewController(_ viewController: NSViewController,
                  animator animator: NSViewControllerPresentationAnimator)

它按预期工作.

这篇文章提供了更多的见解:对ViewController进行动画自定义演示在OS X Yosemite中

This post provides additional insight: Animate custom presentation of ViewController in OS X Yosemite

以此为参考,到目前为止,这是我的尝试:

Using that as a reference, here's my attempt so far:

class FadeSegue: NSStoryboardSegue {

    override func perform() {
        super.perform()
        sourceController.presentViewController(destinationController as NSViewController,
            animator: FadeTransitionAnimator())
    }
}


class FadeTransitionAnimator: NSObject, NSViewControllerPresentationAnimator {

    func animatePresentationOfViewController(toViewController: NSViewController, fromViewController: NSViewController) {

        toViewController.view.wantsLayer = true
        toViewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay
        toViewController.view.alphaValue = 0
        fromViewController.view.addSubview(toViewController.view)
        toViewController.view.frame = fromViewController.view.frame

        NSAnimationContext.runAnimationGroup({ context in
            context.duration = 2
            toViewController.view.animator().alphaValue = 1
            }, completionHandler: nil)
    }

    func animateDismissalOfViewController(viewController: NSViewController, fromViewController: NSViewController) {

        viewController.view.wantsLayer = true
        viewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay

        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            context.duration = 2
            viewController.view.animator().alphaValue = 0
            }, completionHandler: {
                viewController.view.removeFromSuperview()
        })
    }

}

推荐答案

问题似乎出在NSStoryboardSegue的Swift的子类化"上.如果使用Objective-C实现相同的功能,那么一切都会按预期进行.问题是特定地 与您的FadeSeque类有关.动画对象可以在Objective-C Swift中正常工作.

The problem appears to be with the Swift 'subclassing' of NSStoryboardSegue. If you implement the same functionality using Objective-C, everything works as expected. The problem is specifically with your FadeSeque class. The animator object works fine in either Objective-C or Swift.

所以这个:

class FadeSegue: NSStoryboardSegue {
    override func perform() {
    super.perform()
    sourceController.presentViewController(destinationController as NSViewController,
        animator: FadeTransitionAnimator())
    }
} 

如果作为Objective-C类提供,则将起作用:

Will work if provided as an Objective-C class:

@interface MyCustomSegue : NSStoryboardSegue
@end

@implementation FadeSegue

- (void)perform {
   id animator = [[FadeTransitionAnimator alloc] init];
    [self.sourceController presentViewController:self.destinationController
                                        animator:animator];
   }
   @end

(我认为您不需要致电super)

(I don't think you need to call super )

由于似乎没有任何地方对此进行记录,因此我在github上做了一个小项目演示:

As this doesn't seem to be documented much anywhere, I have made a small project on github to demonstrate:

  • NSStoryboardSegue从一个NSViewController过渡到同一Storyboard中的另一个
  • NSViewController当前:使用情节提要Segue对单独的基于Xib的NSViewController 实现相同效果的方法 presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior:
    presentViewControllerAsSheet:
    presentViewControllerAsModalWindow:
    presentViewController:animator:
  • Objective-C和Swift中的动画器和segue对象
  • NSStoryboardSegue transitions from one NSViewController to another in the same Storyboard
  • NSViewController present: methods to achieve the same affect to a separate Xib-based NSViewController without using a Storyboard Segue presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior:
    presentViewControllerAsSheet:
    presentViewControllerAsModalWindow:
    presentViewController:animator:
  • animator and segue objects in Objective-C and Swift

编辑

好的,我已经找到了EXC_BAD_ACCESS问题.在堆栈跟踪中查看,似乎与(Objective-C)NSString到(Swift)字符串转换有关.

OK I've tracked down the EXC_BAD_ACCESS issue. Looking in the stack trace it seemed to have something to do with (Objective-C) NSString to (Swift) String conversion.

这使NSStoryboardSegueidentifier属性产生了疑问.在情节提要中设置Segues时使用此功能,而在用代码创建的Custom Segues中则没有太大用处.但是,事实证明,如果在情节提要中将标识符设置为任何字符串值,甚至是",崩溃都将消失.

That made wonder about the identifier property of NSStoryboardSegue. This is used when setting up segues in the Storyboard, and is not so useful in Custom segues created in code. However, it turns out that if you set an identifier in the storyboard to any string value, even "", the crash disappears.

identifier属性是Objective-C中的NSString *

The identifier property is an NSString* in Objective-C

@property(readonly, copy) NSString *identifier

和Swift中的可选String:

and an optional String in Swift:

var identifier: String? { get }

请注意只读状态.您只能在初始化对象时设置标识符.

Note the read-only status. You can only set the identifier on initialising the object.

NSStoryboardSegue的指示符初始化程序在Objective-C中如下所示:

The designator initialiser for NSStoryboardSegue looks like this in Objective-C:

- (instancetype)initWithIdentifier:(NSString *)identifier
                            source:(id)sourceController
                       destination:(id)destinationController

和Swift:

init(identifier identifier: String,
         source sourceController: AnyObject,
    destination destinationController: AnyObject)

请注意Swift初始化程序中的非可选要求.问题和崩溃就在其中.如果您不故意在情节提要中设置标识符,则将使用该标识符的nil值来调用Custom segue的指定初始化程序.在Objective-C中这不是问题,但对Swift来说是个坏消息.

Note the non-optional requirement in the Swift initialiser. Therein lies the problem and the crash. If you don't deliberately set an identifier in the storyboard, the Custom segue's designated initialiser will be called using a nil value for the identifier. Not a problem in Objective-C, but bad news for Swift.

快速解决方案是确保您在情节提要中设置标识符字符串.对于更健壮的解决方案,事实证明您可以在自定义子类中覆盖指定的初始化程序,以截取零值的字符串.然后,您可以将其填充为默认值,然后再传递给super的指定初始化程序:

The quick solution is to ensure you set an identifier string in Storyboard. For a more robust solution, it turns out that you can override the designated initialiser in your custom subclass to intercept a nil-valued string. Then you can fill it in with a default value before passing on to super's designated initialiser:

override init(identifier: String?, 
              source sourceController: AnyObject,
              destination destinationController: AnyObject) {
        var myIdentifier : String
        if identifier == nil {
            myIdentifier = ""
        } else {
            myIdentifier = identifier!
        }
    super.init(identifier: myIdentifier, 
                source: sourceController, 
                destination: destinationController)
}

我已经更新了示例项目以反映该解决方案

I have updated the sample project to reflect this solution

这篇关于NSStoryboardSegue示例代码(Yosemite故事板)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆