【问题标题】:NSStoryboardSegue sample code (Yosemite Storyboard)NSStoryboardSegue 示例代码(优胜美地故事板)
【发布时间】:2015-01-08 16:38:34
【问题描述】:

OS X Yosemite 引入 NSStoryboardSegue

“A storyboard segue specifies a transition or containment relationship between two scenes in a storyboard…”


更新:

• 如果我尝试在 Yosemite 的 Storyboard 中使用 NSStoryboardSegue 子类,它会因 SIGABRT 而崩溃。

• 如果我忽略 segue,并使用指定的自定义动画器手动呈现视图控制器以进行演示和关闭,

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

它按预期工作。


这篇文章提供了额外的见解:Animate custom presentation of ViewController in OS X Yosemite

以此作为参考,这是我迄今为止的尝试:

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()
        })
    }

}

【问题讨论】:

  • 你有没有想过这个问题?它不需要故事板,因为默认演示动画与 nib 一起使用。我想这样做是为了最终以更少的样板更轻松地加载视图
  • @uchuugaka - 见我的answer,并附上sample project
  • @foundry 写得真好!在问了之后,我实际上自己想出了一点。我发现它非常简单,并表明它实际上只是一个股票方法存根
  • 至少对我而言,将其用作加载视图的位置并将其粘贴在窗口或弹出窗口或其他任何东西中并设置退出策略的效果很好。

标签: objective-c macos swift osx-yosemite


【解决方案1】:

问题似乎出在 NSStoryboardSegue 的 Swift“子类化”上。如果您使用 Objective-C 实现相同的功能,一切都会按预期进行。问题是特别是你的FadeSeque 类。 animator 对象在 Objective-C Swift 中都能正常工作。

所以这个:

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

如果以 Objective-C 类的形式提供,则可以使用:

@interface MyCustomSegue : NSStoryboardSegue
@end

@implementation FadeSegue

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

(我认为你不需要打电话给super

由于这似乎没有在任何地方记录太多,I have made a small project on github 进行演示:

  • NSStoryboardSegue 在同一个 Storyboard 中从一个 NSViewController 转换到另一个
  • NSViewController 存在:在不使用 Storyboard Segue 的情况下 对单独的基于 Xib 的 NSViewController 实现相同效果的方法 presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior:
    presentViewControllerAsSheet:
    presentViewControllerAsModalWindow:
    presentViewController:animator:
  • Objective-C 和 Swift 中的动画师和 segue 对象

编辑

好的,我已经找到了 EXC_BAD_ACCESS 问题。查看堆栈跟踪,它似乎与 (Objective-C) NSString 到 (Swift) String 转换有关。

这让人对NSStoryboardSegueidentifier 属性感到好奇。这在 Storyboard 中设置 segues 时使用,在代码中创建的自定义 segues 中不是很有用。但是,事实证明,如果您将情节提要中的标识符设置为任何字符串值,甚至是“”,崩溃就会消失。

identifier 属性是 Objective-C 中的 NSString*

@property(readonly, copy) NSString *identifier

以及 Swift 中的可选字符串:

var identifier: String? { get }

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

NSStoryboardSegue 的指示符初始化器在 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 值调用自定义 segue 的指定初始化程序。在 Objective-C 中不是问题,但对 Swift 来说是个坏消息。

快速解决方案是确保您在 Storyboard 中设置标识符字符串。对于更健壮的解决方案,事实证明,您可以在自定义子类中覆盖指定的初始化程序以拦截一个零值字符串。然后你可以在传递给 super 的指定初始化程序之前用默认值填充它:

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)
}

我有updated the sample project 反映这个解决方案

【讨论】:

  • 请注意,您可以使用空合并而不是使用临时合并:identifier ?? "" 表示“identifier 如果它不是 nil,否则 ""
  • Objective C 上的示例崩溃,[ViewController performSelector:withObject:]:消息发送到已释放实例 0x6000000d06f0,
【解决方案2】:

同样的问题出现在我身上,因为我忘记了对 segue 进行标识。

之后,我的 segue 子类就可以正常工作了。

【讨论】:

    【解决方案3】:

    强烈建议您查看Apple documentation。如果您深入研究一下,您会注意到在 perform 方法中,您可以覆盖动画等:

    SWIFT

    func perform()
    

    目标-C

    - (void)perform
    

    “您可以在您的 NSStoryboardSegue 子类中重写此方法,以在故事板 segue 的开始/包含控制器和结束/包含控制器之间执行自定义动画。通常,您将使用 Core Animation 从一组设置动画视图到下一个。对于更复杂的动画,您可以拍摄两个视图层次结构的快照图像并操作图像而不是视图对象。*

    无论您如何执行动画,您都有责任将目标视图控制器或窗口控制器(及其包含的视图)安装在正确的位置,以便它可以处理事件。通常,这需要调用 NSViewController 类中的一种表示方法。"

    您也可以看看野外的一些iOS UIStoryboardSegue examples,您应该会发现它们非常相似。

    【讨论】:

    • 请原谅我的不理解……我仔细查看了 Apple 文档,这就是我在原始帖子中引用它的原因。虽然它在概念上与 UIKit 对应物是平行的,但我无法得出最终的和谐。
    • 哎呀,没有意识到你链接到苹果文档很抱歉;)。到目前为止,您是否有任何代码不起作用?
    • 好吧,那么到底是什么不工作呢?您只是无法使用它,还是行为异常?
    • 奇怪的是,如果我尝试在情节提要中使用它(通过将其指定为自定义 segue),它会在执行时立即崩溃。崩溃本质上是通用的,不提供额外的洞察力。没有任何官方指导/示例代码,我没有追索权。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    相关资源
    最近更新 更多