2010-06-08 50 views
16

是的,我知道这违背了整个MVC原则!创建一个没有NIB文件的Cocoa应用程序

但是,我只是想掀起一个非常平凡的应用程序 - 我几乎实现了它。但是,我有一个问题...我创建一个空项目,将所有框架复制并设置构建设置 - 并且我得到有关可执行文件的错误或缺少可执行文件。构建设置都很好,但它告诉我没有可执行文件 - 它会生成+运行正常。但它不运行。也没有错误 - 它看起来运行速度非常快,干净!除非我尝试运行GDB我需要给它一个文件,其中第一个礼貌地告诉我..

Running… 
No executable file specified. 
Use the "file" or "exec-file" command. 

所以我创建了一个Cocoa应用程序,删除了所有东西,我并不需要(也就是MainMenu.xib文件..),现在我可以完美地编译我的代码。但是它死抱怨它的

“无法加载笔尖文件:MainMenu的,退出”

我已经通过项目符号消失了,看到代码实际上在护理文件严重依赖,甚至如果你不以代码方式触摸它。 (MVC再次我猜..)

是否有一个简单的方法来编译只是你的代码,没有添加NIB文件,只是你写的代码和你添加的框架?我认为这将是一个空白的项目,但我的经验告诉我,否则?!

+6

您是不是要找 “程序?” – 2010-06-08 16:23:45

+1

*编程*并不意味着反对MVC。 MVC就是如何组织组件代码,而IB/NIB/Storyboard与MVC无关。它们只是帮助您绘制UI的工具。你可以根本不用这些工具来完成MVC。 – Eonil 2014-10-12 05:54:18

回答

10

当然,你可以只写代码而不使用Interface Builder。

你检查了你的Info.plist吗?默认情况下,MainMenu.xib中有一个条目,它可能是它抱怨的引用。

+0

我没有碰过Interface Builder!那是什么烦扰我,从Info.plist删除条目解决了这一点 - 谢谢!是一个非常快速的答复! :D – Moddy 2010-06-08 12:55:23

7

问题可能是您的main功能(main.m)中仍然呼叫NSApplicationMain。如果您没有加载如MainMenu.nib这样的笔尖,则可能需要将电话拨到NSApplicationMain,并在main中编写自己的代码以启动该应用程序。

+0

我希望这样做,但我认为NSApplicationMain必须从.plist文件取得.nib信息 - 因为它似乎运行良好!欢迎尽快回复! – Moddy 2010-06-08 12:59:53

+0

备案 - 在我重新实施NSApplication之前,仍然有一两个问题没有注意到!所以你是对的,再次欢呼。 (任何人想知道 - “[NSApplication shareApplication]” - 紧接着 - “[NSApp运行” - 足以修复最终的错误) – Moddy 2010-06-08 13:25:55

-3

不要使用的NSApplication和NSApp表示...

你只需要指定一个实现了UIApplicationDelegate协议类:

UIApplicationMain(argc, argv, nil, @"Name of your class"); 
+2

这是iOS代码。他特意要求Mac代码。 – CajunLuke 2011-07-15 14:32:18

34

这是我在我的应用程序使用的方法。对不起格式化,我希望你能把它搞清楚。我不知道如何关闭这里的自动格式。

当然会有这个示例中没有功能主菜单,这是太多的代码对我来说,在这样一个帖子写:P - 对不起,出来做一些研究;)

这应该让你开始:

AppDelegate.h

@interface MyApplicationDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> { 
    NSWindow * window; 
} 
@end 

AppDelegate中。米

@implementation MyApplicationDelegate : NSObject 
- (id)init { 
    if (self = [super init]) { 
     // allocate and initialize window and stuff here .. 
    } 
    return self; 
} 

- (void)applicationWillFinishLaunching:(NSNotification *)notification { 
    [window makeKeyAndOrderFront:self]; 
} 

- (void)dealloc { 
    [window release]; 
    [super dealloc]; 
} 

@end 

的main.m

#import "AppDelegate.h" 

int main(int argc, char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    NSApplication * application = [NSApplication sharedApplication]; 

    MyApplicationDelegate * appDelegate = [[[[MyApplicationDelegate]alloc] init] autorelease]; 

    [application setDelegate:appDelegate]; 
    [application run]; 

    [pool drain]; 

    return EXIT_SUCCESS; 
} 
+0

我建议这个解决方案适用于那些不想在Cocoa应用程序中使用NIB的人。一个典型的例子是作为登录项目的辅助“代理”设置。 – Arvin 2012-08-15 13:17:37

+1

非常好,谢谢!我意识到这是一个3年的答案,但我想知道是否可以详细说明为什么实例化NSAutoreleasePool,特别是返回“EXIT_SUCCESS”是必需的。 – 2013-06-13 03:09:59

+2

对于ARC代码,请使用@autoreleasepool块代替实例化并排空/释放NSAutoreleasePool,如下所述:https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsautoreleasepool_Class/参考/ Reference.html – 2013-06-13 03:19:56

19
int main() { 
    [NSAutoreleasePool new]; 
    [NSApplication sharedApplication]; 
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 
    id menubar = [[NSMenu new] autorelease]; 
    id appMenuItem = [[NSMenuItem new] autorelease]; 
    [menubar addItem:appMenuItem]; 
    [NSApp setMainMenu:menubar]; 
    id appMenu = [[NSMenu new] autorelease]; 
    id appName = [[NSProcessInfo processInfo] processName]; 
    id quitTitle = [@"Quit " stringByAppendingString:appName]; 
    id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle 
    action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; 
    [appMenu addItem:quitMenuItem]; 
    [appMenuItem setSubmenu:appMenu]; 
    id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) 
    styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO] 
    autorelease]; 
    [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; 
    [window setTitle:appName]; 
    [window makeKeyAndOrderFront:nil]; 
    [NSApp activateIgnoringOtherApps:YES]; 
    [NSApp run]; 
    return 0; 
} 
+3

这个极简主义的应用程序的一个很好的解释是在http://www.cocoawithlove.com/2010/09/minimalist-cocoa- programming.html – Buzzy 2012-12-06 00:21:52

+0

真棒!非常感谢!!!欠你一个。 – 2013-11-06 23:21:46

+0

正如@Buzzy所述,这个答案实际上是从http://www.cocoawithlove.com/2010/09/minimalist-cocoa-programming.html – robobrobro 2017-07-28 00:53:23

10

虽然这是一个几年的老问题...

这里是最小的代码片段来引导斯威夫特Cocoa应用程序。

import AppKit 

final class ExampleApplicationController: NSObject, NSApplicationDelegate { 
    let window1 = NSWindow() 

    func applicationDidFinishLaunching(aNotification: NSNotification) { 
     window1.setFrame(CGRect(x: 0, y: 0, width: 800, height: 500), display: true) 
     window1.makeKeyAndOrderFront(self) 
    } 

    func applicationWillTerminate(aNotification: NSNotification) { 
    } 

} 

autoreleasepool {() ->() in 
    let app1  = NSApplication.sharedApplication() 
    let con1  = ExampleApplicationController() 

    app1.delegate = con1 
    app1.run() 
} 

另外,我正在维护一大堆Cocoa的编程示例,包括bootstrapping,窗口,菜单创建。

查看所需的语言子项目。

+0

我收到一个错误'表达式不允许在autoreleasepool的最高层级上。 Xcode 6.4。 – hiroshi 2015-08-29 12:24:56

+1

我发现文件名必须是'main.swift'。 – hiroshi 2015-08-29 12:39:05

3

这里是Casper's solution,更新的ARC按Marco's suggestion

#import <Cocoa/Cocoa.h> 
#import "AppDelegate.h" 

int main(int argc, char * argv[]) { 
    @autoreleasepool { 
     NSApplication *application = [NSApplication sharedApplication]; 
     AppDelegate *appDelegate = [[AppDelegate alloc] init]; 
     [application setDelegate:appDelegate]; 
     [application run]; 
    } 
    return EXIT_SUCCESS; 
} 
0

为autoreleasepool样本SWIFT代码段provided above不会在现代的Xcode工作。相反,您需要摆脱App Delegate源文件中的@NSApplicationMain(如果有)(Xcode现在为新项目添加这些文件),并添加包含以下内容的main.swift文件:

顶部上面的代码示例不再适用于最新版本的Xcode。而是使用此:

import Cocoa 

let delegate = ExampleApplicationController() //alloc main app's delegate class 
NSApplication.shared().delegate = delegate //set as app's delegate 

let ret = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) 
+0

从技术上讲,旧帖子应该被编辑(社区wiki),但是你没有足够的声望。所以我想一个新的答案是可以的。您可以通过明确链接“上面提供的答案”来改进您的答案。 – MikeJRamsey56 2016-12-11 20:06:44

3

7年来不及参加聚会,但有点简单单文件代码

#import <Cocoa/Cocoa.h> 

@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> { 
    NSWindow* window; 
} 
@end 

@implementation AppDelegate : NSObject 
- (id)init { 
    if (self = [super init]) { 
     window = [NSWindow.alloc initWithContentRect: NSMakeRect(0, 0, 200, 200) 
              styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskClosable 
              backing: NSBackingStoreBuffered 
               defer: NO]; 
    } 
    return self; 
} 

- (void)applicationWillFinishLaunching:(NSNotification *)notification { 
    window.title = NSProcessInfo.processInfo.processName; 
    [window cascadeTopLeftFromPoint: NSMakePoint(20,20)]; 
    [window makeKeyAndOrderFront: self]; 
} 

@end 

int main(int argc, const char * argv[]) { 
    NSApplication* app = NSApplication.sharedApplication; 
    app.ActivationPolicy = NSApplicationActivationPolicyRegular; 
    NSMenuItem* item = NSMenuItem.new; 
    NSApp.mainMenu = NSMenu.new; 
    item.submenu = NSMenu.new; 
    [app.mainMenu addItem: item]; 
    [item.submenu addItem: [[NSMenuItem alloc] initWithTitle: [@"Quit " stringByAppendingString: NSProcessInfo.processInfo.processName] action:@selector(terminate:) keyEquivalent:@"q"]]; 
    AppDelegate* appDelegate = AppDelegate.new; // cannot collapse this and next line because .dlegate is weak 
    app.delegate = appDelegate; 
    (void)app.run; 
    return 0; 
} 
1

斯威夫特4版本NSToolbarNSMenu(与事件处理程序,而不是代表):

文件main.swift

autoreleasepool { 
    // Even if we loading application manually we need to setup `Info.plist` key: 
    // <key>NSPrincipalClass</key> 
    // <string>NSApplication</string> 
    // Otherwise Application will be loaded in `low resolution` mode. 
    let app = Application.shared 
    app.setActivationPolicy(.regular) 
    app.run() 
} 

文件:Application.swift

class Application: NSApplication { 

    private lazy var mainWindowController = MainWindowController() 
    private lazy var mainAppMenu = MainMenu() 

    override init() { 
     super.init() 
     setupUI() 
     setupHandlers() 
    } 

    required init?(coder: NSCoder) { 
     super.init(coder: coder) // This will never called. 
    } 
} 

extension Application: NSApplicationDelegate { 

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 
     return true 
    } 

    func applicationDidFinishLaunching(_ aNotification: Notification) { 
     mainWindowController.showWindow(nil) 
    } 

} 

extension Application { 

    private func setupUI() { 
     mainMenu = mainAppMenu 
    } 

    private func setupHandlers() { 
     delegate = self 
     mainAppMenu.eventHandler = { [weak self] in 
     switch $0 { 
     case .quit: 
      self?.terminate(nil) 
     } 
     } 
    } 

} 

文件MainWindowController.swift

class MainWindowController: NSWindowController { 

    private (set) lazy var viewController = MainViewController() 
    private (set) lazy var mainToolbar = MainToolbar(identifier: NSToolbar.Identifier("ua.com.wavelabs.Decoder:mainToolbar")) 

    init() { 
     let window = NSWindow(contentRect: CGRect(x: 400, y: 200, width: 800, height: 600), 
          styleMask: [.titled, .closable, .resizable, .miniaturizable], 
          backing: .buffered, 
          defer: true) 
     super.init(window: window) 


     let frameSize = window.contentRect(forFrameRect: window.frame).size 
     viewController.view.setFrameSize(frameSize) 
     window.contentViewController = viewController 

     window.titleVisibility = .hidden 
     window.toolbar = mainToolbar 

     setupHandlers() 
    } 

    required init?(coder: NSCoder) { 
     super.init(coder: coder) 
    } 
} 

extension MainWindowController { 

    private func setupHandlers() { 
     mainToolbar.eventHandler = { 
     print($0) 
     } 
    } 
} 

文件MainViewController.swift

class MainViewController: NSViewController { 

    init() { 
     super.init(nibName: nil, bundle: nil) 
    } 

    required init?(coder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func loadView() { 
     view = NSView() 
     view.wantsLayer = true 
     view.layer?.backgroundColor = NSColor.magenta.cgColor 
    } 
} 

文件MainToolbar 。迅速

class MainToolbar: NSToolbar { 

    enum Event: Int { 
     case toggleSidePanel 
    } 

    let toolbarDelegate = GenericDelegate() 

    var eventHandler: ((MainToolbar.Event) -> Void)? 

    override init(identifier: NSToolbar.Identifier) { 
     super.init(identifier: identifier) 
     setupUI() 
     setupHandlers() 
    } 
} 

extension MainToolbar { 

    private func setupUI() { 
     allowsUserCustomization = true 
     autosavesConfiguration = true 
     displayMode = .iconOnly 
     toolbarDelegate.allowedItemIdentifiers = [.space, .flexibleSpace] 
     toolbarDelegate.selectableItemIdentifiers = [.space, .flexibleSpace] 
     toolbarDelegate.defaultItemIdentifiers = Event.toolbarIDs + [.flexibleSpace] 
    } 

    private func setupHandlers() { 
     delegate = toolbarDelegate 
     toolbarDelegate.makeItemCallback = { [unowned self] id, _ in 
     guard let event = Event(id: id) else { 
      return nil 
     } 
     return self.makeToolbarItem(event: event) 
     } 
    } 

    private func makeToolbarItem(event: Event) -> NSToolbarItem { 
     let item = NSToolbarItem(itemIdentifier: event.itemIdentifier) 
     item.setHandler { [weak self] in 
     guard let event = Event(id: event.itemIdentifier) else { 
      return 
     } 
     self?.eventHandler?(event) 
     } 
     item.label = event.label 
     item.paletteLabel = event.paletteLabel 
     if event.image != nil { 
     item.image = event.image 
     } else if event.view != nil { 
     item.view = event.view 
     } 
     return item 
    } 
} 

extension MainToolbar.Event { 

    init?(id: NSToolbarItem.Identifier) { 
     guard let event = (MainToolbar.Event.allValues.filter { $0.itemIdentifier == id }).first else { 
     return nil 
     } 
     self = event 
    } 

    static var allValues: [MainToolbar.Event] { 
     return [toggleSidePanel] 
    } 

    static var toolbarIDs: [NSToolbarItem.Identifier] { 
     return [toggleSidePanel].map { $0.itemIdentifier } 
    } 

    var itemIdentifier: NSToolbarItem.Identifier { 
     switch self { 
     case .toggleSidePanel: return NSToolbarItem.Identifier("ua.com.wavalabs.toolbar.toggleSidePanel") 
     } 
    } 

    var label: String { 
     switch self { 
     case .toggleSidePanel: return "Toggle Side Panel" 
     } 
    } 

    var view: NSView? { 
     return nil 
    } 

    var image: NSImage? { 
     switch self { 
     case .toggleSidePanel: return NSImage(named: NSImage.Name.folder) 
     } 
    } 

    var paletteLabel: String { 
     return label 
    } 
} 

文件MainMenu.swift

class MainMenu: NSMenu { 

    enum Event { 
     case quit 
    } 

    var eventHandler: ((Event) -> Void)? 

    private lazy var applicationName = ProcessInfo.processInfo.processName 

    init() { 
     super.init(title: "") 
     setupUI() 
    } 

    required init(coder decoder: NSCoder) { 
     super.init(coder: decoder) 
    } 

} 


extension MainMenu { 

    private func setupUI() { 

     let appMenuItem = NSMenuItem() 
     appMenuItem.submenu = appMenu 

     addItem(appMenuItem) 
    } 

    private var appMenu: NSMenu { 
     let menu = NSMenu(title: "") 
     menu.addItem(title: "Quit \(applicationName)", keyEquivalent: "q") { [unowned self] in 
     self.eventHandler?(.quit) 
     } 
     return menu 
    } 

} 

方便扩展

文件NSMenu.swift

extension NSMenu { 

    @discardableResult 
    public func addItem(title: String, keyEquivalent: String, handler: NSMenuItem.Handler?) -> NSMenuItem { 
     let item = addItem(withTitle: title, action: nil, keyEquivalent: keyEquivalent) 
     item.setHandler(handler) 
     return item 
    } 

} 

文件NSMenuItem.swift

extension NSMenuItem { 

    public typealias Handler = (() -> Void) 

    convenience init(title: String, keyEquivalent: String, handler: Handler?) { 
     self.init(title: title, action: nil, keyEquivalent: keyEquivalent) 
     setHandler(handler) 
    } 

    public func setHandler(_ handler: Handler?) { 
     target = self 
     action = #selector(wavelabsActionHandler(_:)) 
     if let handler = handler { 
     ObjCAssociation.setCopyNonAtomic(value: handler, to: self, forKey: &OBJCAssociationKeys.actionHandler) 
     } 
    } 

} 

extension NSMenuItem { 

    private struct OBJCAssociationKeys { 
     static var actionHandler = "com.wavelabs.actionHandler" 
    } 

    @objc private func wavelabsActionHandler(_ sender: NSControl) { 
     guard sender == self else { 
     return 
     } 
     if let handler: Handler = ObjCAssociation.value(from: self, forKey: &OBJCAssociationKeys.actionHandler) { 
     handler() 
     } 
    } 
} 

文件NSToolbar.swift

extension NSToolbar { 

    class GenericDelegate: NSObject, NSToolbarDelegate { 

     var selectableItemIdentifiers: [NSToolbarItem.Identifier] = [] 
     var defaultItemIdentifiers: [NSToolbarItem.Identifier] = [] 
     var allowedItemIdentifiers: [NSToolbarItem.Identifier] = [] 

     var eventHandler: ((Event) -> Void)? 
     var makeItemCallback: ((_ itemIdentifier: NSToolbarItem.Identifier, _ willBeInserted: Bool) -> NSToolbarItem?)? 
    } 
} 

extension NSToolbar.GenericDelegate { 

    enum Event { 
     case willAddItem(item: NSToolbarItem, index: Int) 
     case didRemoveItem(item: NSToolbarItem) 
    } 
} 

extension NSToolbar.GenericDelegate { 

    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, 
       willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { 
     return makeItemCallback?(itemIdentifier, flag) 
    } 

    func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { 
     return defaultItemIdentifiers 
    } 

    func toolbarAllowedItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { 
     return allowedItemIdentifiers 
    } 

    func toolbarSelectableItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { 
     return selectableItemIdentifiers 
    } 

    // MARK: Notifications 

    func toolbarWillAddItem(_ notification: Notification) { 
     if let toolbarItem = notification.userInfo?["item"] as? NSToolbarItem, 
     let index = notification.userInfo?["newIndex"] as? Int { 
     eventHandler?(.willAddItem(item: toolbarItem, index: index)) 
     } 
    } 

    func toolbarDidRemoveItem(_ notification: Notification) { 
     if let toolbarItem = notification.userInfo?["item"] as? NSToolbarItem { 
     eventHandler?(.didRemoveItem(item: toolbarItem)) 
     } 
    } 
} 

文件NSToolbarItem.swift

extension NSToolbarItem { 

    public typealias Handler = (() -> Void) 

    public func setHandler(_ handler: Handler?) { 
     target = self 
     action = #selector(wavelabsActionHandler(_:)) 
     if let handler = handler { 
     ObjCAssociation.setCopyNonAtomic(value: handler, to: self, forKey: &OBJCAssociationKeys.actionHandler) 
     } 
    } 

} 

extension NSToolbarItem { 

    private struct OBJCAssociationKeys { 
     static var actionHandler = "com.wavelabs.actionHandler" 
    } 

    @objc private func wavelabsActionHandler(_ sender: NSControl) { 
     guard sender == self else { 
     return 
     } 
     if let handler: Handler = ObjCAssociation.value(from: self, forKey: &OBJCAssociationKeys.actionHandler) { 
     handler() 
     } 
    } 
} 

文件ObjCAssociation.swift

public struct ObjCAssociation { 

    public static func value<T>(from object: AnyObject, forKey key: UnsafeRawPointer) -> T? { 
     return objc_getAssociatedObject(object, key) as? T 
    } 

    public static func setAssign<T>(value: T?, to object: Any, forKey key: UnsafeRawPointer) { 
     objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_ASSIGN) 
    } 
    public static func setRetainNonAtomic<T>(value: T?, to object: Any, forKey key: UnsafeRawPointer) { 
     objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 
    } 
    public static func setCopyNonAtomic<T>(value: T?, to object: Any, forKey key: UnsafeRawPointer) { 
     objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_COPY_NONATOMIC) 
    } 
    public static func setRetain<T>(value: T?, to object: Any, forKey key: UnsafeRawPointer) { 
     objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN) 
    } 
    public static func setCopy<T>(value: T?, to object: Any, forKey key: UnsafeRawPointer) { 
     objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_COPY) 
    } 
} 
相关问题