2010-06-08 101 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) 
    } 
} 
相關問題