在使用纯代码构建UI界面时,如果只是把NSViewController的View简单的Add到NSWindow中,则导致无法监听到action的。例如如下代码:

// mainwindow
let result = MainWindow(contentRect: AppConfig.windowRect, styleMask: .titled, backing: .buffered, defer: false)
result.styleMask.insert(.closable)
result.styleMask.insert(.miniaturizable)
result.title = NSLocalizedString("HomeTitle", comment: "")
result.titleVisibility = .visible
result.titlebarAppearsTransparent = false
result.delegate = result
result.center()
        
let viewController = MainViewController()
result.contentView?.addSubview(viewController.view)


// MainViewController 
... ...

slPasswordLength.target = self
slPasswordLength.action = #selector(onChangedPasswordLength(sender:))

... ...

@objc private func onChangedPasswordLength(sender: NSSlider) {
        tfPasswordLengthValue.stringValue = "\(sender.integerValue)"
        scStepper.intValue = sender.intValue
    }

错误的原因是在result.contentView?.addSubview(viewController.view)这一句,仅仅将view添加进去,正确的做法应该是将整个ViewController设置为MainWindow的contentViewController,如下:

let result = MainWindow(contentRect: AppConfig.windowRect, styleMask: .titled, backing: .buffered, defer: false)
result.styleMask.insert(.closable)
result.styleMask.insert(.miniaturizable)
result.title = NSLocalizedString("HomeTitle", comment: "")
result.titleVisibility = .visible
result.titlebarAppearsTransparent = false
result.delegate = result
result.center()
        
let viewController = MainViewController()
result.contentViewController = viewController

在开发Mac OS App的时候如果想使用自定义的字体,并且在发布的时候也带上自定义的字体库,则需要如下几个步骤:

  • 添加字体文件到Xcode的项目中
  • 修改Info.plist

1. 添加字体文件

将字体文件拖拽(添加)到项目的资源库中。范例如下图:

2. 修改Info.plist文件

新增Fonts provided by application及Application fonts resource path两项。

  • Fonts provided by application选Array类型,每个item后填上一个字体文件的路径,新增了多少个字体文件,就填写多少个item
  • Application fonts resource path选String类型,填上字体文件所在目录路径即可。

注意:Application fonts resource path是Mac OS App项目必填的,否则找不到字体文件,这点是与iOS项目不一样的,iOS项目只需要填写Fonts provided by application即可。范例如下图:

完成上述两个步骤,即可使用自定义字体了。

extension NSFont {
    class func mainBoldFont(size: CGFloat) -> NSFont {
        let font = NSFont(name: "FZCUJINLJW--GB1-0", size: size)
        return font ?? NSFont.systemFont(ofSize: size)
    }
    
    class func mainFont(size: CGFloat) -> NSFont {
        let font = NSFont(name: "FZXIJINLJW--GB1-0", size: size)
        return font ?? NSFont.systemFont(ofSize: size)
    }
}

Mac OS App的storyboard中无法直接使用自定义的字体,但是可以在代码中使用,这个问题我没找到原因,如果您找到了方法请告知我。谢谢!

PS: 查看所有可用字体代码片段

let manager = NSFontManager.shared
for name: String in manager.availableFonts {
    print("font name=====" + name)
}

During startup – Warning messages:
1: Setting LC_CTYPE failed, using “C”
2: Setting LC_COLLATE failed, using “C”
3: Setting LC_TIME failed, using “C”
4: Setting LC_MESSAGES failed, using “C”
5: Setting LC_PAPER failed, using “C”
[R.app GUI 1.50 (6126) x86_64-apple-darwin9.8.0]

WARNING: You’re using a non-UTF8 locale, therefore only ASCII characters will work. Please read R for Mac OS X FAQ (see Help) section 9 and adjust your system preferences accordingly.

 

answer:

  1. Open Terminal
  2. Write or paste in: defaults write org.R-project.R force.LANG en_US.UTF-8
  3. Close Terminal
  4. Start R

在安装fir-cli时出现了如下错误:


$ gem install fir-cli

Fetching: thor-0.20.0.gem (100%)

ERROR: While executing gem ... (Gem::FilePermissionError)

You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.

解决办法:


sudo gem install -n /usr/local/bin fir-cli

One of the core components of Mac OS X is launchd, and it turns out it can do some cool things.

I particularly like the idea of using QueueDirectories to monitor and act upon files dropped into a directory, without having to run any extra daemons. The files could be uploaded to S3, transcoded to a different video format, gzipped… anything.

Anyway, I recently fell into the launchd documentation, and came out with this write-up. Let me know if you find it useful.

Overview

The first thing that the Mac OS kernel runs on boot is launchd, which bootstraps the rest of the system by loading and managing various daemons, agents, scripts and other processes. The launchd man page clarifies the difference between a daemon and an agent:

In the launchd lexicon, a “daemon” is, by definition, a system-wide service of which there is one instance for all clients. An “agent” is a service that runs on a per-user basis. Daemons should not attempt to display UI or interact directly with a user’s login session. Any and all work that involves interacting with a user should be done through agents.

Daemons and agents are declared and configured by creating .plist files in various locations of the system:

~/Library/LaunchAgents         Per-user agents provided by the user.
/Library/LaunchAgents          Per-user agents provided by the administrator.
/Library/LaunchDaemons         System-wide daemons provided by the administrator.
/System/Library/LaunchAgents   Per-user agents provided by OS X.
/System/Library/LaunchDaemons  System-wide daemons provided by OS X.

Perhaps best of all, launchd is open source under the Apache License 2.0. You can currently find the latest source code on the Apple Open Source site.

launchd as cron

The Mac OS crontab man page says:

Although cron(8) and crontab(5) are officially supported under Darwin,
their functionality has been absorbed into launchd(8), which provides a
more flexible way of automatically executing commands.

Turns out launchd has a simple StartInterval <integer> property, which starts the job every N seconds. However the true cron-like power lies in StartCalendarInterval:

StartCalendarInterval <dictionary of integers or array of dictionary of integers>

This optional key causes the job to be started every calendar interval as
specified. Missing arguments are considered to be wildcard. The semantics
are much like crontab(5).  Unlike cron which skips job invocations when the
computer is asleep, launchd will start the job the next time the computer
wakes up.  If multiple intervals transpire before the computer is woken,
those events will be coalesced into one event upon wake from sleep.

     Minute <integer>
     The minute on which this job will be run.

     Hour <integer>
     The hour on which this job will be run.

     Day <integer>
     The day on which this job will be run.

     Weekday <integer>
     The weekday on which this job will be run (0 and 7 are Sunday).

     Month <integer>
     The month on which this job will be run.

Lets find the shortest example of this in action:

pda@paulbook ~ > grep -rl StartCalendarInterval \
                   /Library/Launch* /System/Library/Launch* | \
                   xargs wc -l | sort -n | head -n1 | awk '{print $2}' | xargs cat

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>com.apple.gkreport</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/gkreport</string>
        </array>
        <key>StartCalendarInterval</key>
        <dict>
                <key>Minute</key><integer>52</integer>
                <key>Hour</key><integer>3</integer>
                <key>WeekDay</key><integer>5</integer>
        </dict>
</dict>
</plist>

Better than cron? Apart from better handling of skipped jobs after system wake, it also supports per-job environment variables, which can save writing wrapper scripts around your cron jobs:

EnvironmentVariables <dictionary of strings>

This optional key is used to specify additional environmental variables to
be set before running the job.

So, anything XML is obviously worse than 0 52 3 * 5 /path/to/command, but launchd is packing more features than cron, so it can pull it off.

launchd as a filesystem watcher

Apart from having an awesome daemon/agent manager, Mac OS X also has an excellent Mail Transport Agent called postfix. There’s a good chance your ISP runs the same software to handle millions of emails every day. We’ll be using it as an example of how launchd can start jobs based on filesystem changes.

Because your laptop isn’t, and shouldn’t be, a mail server, you don’t want postfix running all the time. But when messages are injected into it, e.g. by a script shelling out to /usr/sbin/sendmail or /usr/bin/mail, you want them to be delivered straight away.

Here’s how Mac OS X does it (/System/Library/LaunchDaemons/org.postfix.master.plist):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.postfix.master</string>
    <key>Program</key>
    <string>/usr/libexec/postfix/master</string>
    <key>ProgramArguments</key>
    <array>
        <string>master</string>
        <string>-e</string>
        <string>60</string>
    </array>
    <key>QueueDirectories</key>
    <array>
        <string>/var/spool/postfix/maildrop</string>
    </array>
    <key>AbandonProcessGroup</key>
    <true/>
</dict>
</plist>

We’ll start with the simple part. ProgramArguments passes -e 60 to postfix, described thusly:

-e exit_time
              Terminate the master process after exit_time seconds.
              Child processes terminate at their convenience.

So postfix is told to exit after running for 60 seconds. The mystery (to me, earlier today, at least) is how it gets started. It could be on a cron-like schedule, but (a) it isn’t, (b) that would suck, and (c) it would result in delayed mail delivery. It turns out the magic lies in QueueDirectory, which I initially overlooked thinking it was a postfix option. The launchd.plist man page says:

WatchPaths <array of strings>
This optional key causes the job to be started if any one of the listed
paths are modified.

QueueDirectories <array of strings>
Much like the WatchPaths option, this key will watch the paths for
modifications. The difference being that the job will only be started if
the path is a directory and the directory is not empty.

The Launchd Wikipedia page actually goes into more detail:

QueueDirectories
Watch a directory for new files. The directory must be empty to begin with,
and must be returned to an empty state before QueueDirectories will launch
its task again.

So launchd can monitor a directory for new files, and then trigger an agent/daemon to consume them. In this case, the postfix sendmail(1) man page tells us that “Postfix sendmail(1) relies on the postdrop(1) command to create a queue file in the maildrop directory”, and the man page for postdrop(1) tells us that /var/spool/postfix/maildrop is the maildrop queue. launchd sees new mail there, fires up postfix, and then stops it after 60 seconds. This might cause deferred mail to stay deferred for quite some time, but again; your laptop isn’t a mail server.

launchd as inetd

Tranditionally the inetd and later xinetd “super-server daemon” were used to listen on various ports (e.g. FTP, telnet, …) and launch daemons on-demand to handle in-bound connection, keeping them out of memory at other times. Sounds like something launchd could do…

Lets create a simple inetd-style server at ~/Library/LaunchAgents/my.greeter.plist:

<plist version="1.0">
<dict>
  <key>Label</key><string>my.greeter</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/ruby</string>
    <string>-e</string>
    <string>puts "Hi #{gets.match(/(\w+)\W*\z/)[1]}, happy #{Time.now.strftime("%A")}!"</string>
  </array>
  <key>inetdCompatibility</key><dict><key>Wait</key><false/></dict>
  <key>Sockets</key>
  <dict>
    <key>Listeners</key>
    <dict>
      <key>SockServiceName</key><string>13117</string>
    </dict>
  </dict>
</dict>
</plist>

Load it up and give it a shot:

pda@paulbook ~ > launchctl load ~/Library/LaunchAgents/my.greeter.plist
pda@paulbook ~ > echo "My name is Paul." | nc localhost 13117
Hi Paul, happy Friday!

launchd as god!

You can use launchd to ensure a process stays alive forever using <key>KeepAlive</key><true/>, or stays alive under the following conditions.

  • SuccessfulExit — the previous run exited successfully (or if false, unsuccessful exit).
  • NetworkState — network (other than localhost) is up (or if false, down).
  • PathState — list of file paths exists (or if false, do not exist).
  • OtherJobEnabled — the other named job is enabled (or if false, disabled).

These can be combined with various other properties, for example:

  • WorkingDirectory
  • EnvironmentVariables
  • Umask
  • ThrottleInterval
  • StartOnMount
  • StandardInPath
  • StandardOutPath
  • StandardErrorPath
  • SoftResourceLimits and HardResourceLimits
  • Nice

More?

There’s some more information at developer.apple.com, and the launchd and launchd.plist man pages are worth reading.

link: http://paul.annesley.cc/2012/09/mac-os-x-launchd-is-cool/

打开终端(Terminal),把下面这行命令贴进去,回车。

这个命令的作用就是在证书验证缓存数据库里面清除globalsign下发的缓存。运行结束重启chrome就可以了。
sqlite3 ~/Library/Keychains/*/ocspcache.sqlite3 ‘DELETE FROM responses WHERE responderURI LIKE “tp://%.globalsign.com/%”;’

升级xcode 后 Qt 出问题了,google 找到了解决方法。

http://stackoverflow.com/questions/33728905/qt-creator-project-error-xcode-not-set-up-properly-you-may-need-to-confirm-t

~> Xcode 8

This problem occurs when command line tools are installed after Xcode is installed. What happens is the Xcode-select developer directory gets pointed to /Library/Developer/CommandLineTools.

Step 1:

Point Xcode-select to the correct Xcode Developer directory with the command:

sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer

Step 2:

Confirm the license agreement with the command:

xcodebuild -license

This will prompt you to read through the license agreement. 

Enter agree to accept the terms.

>= Xcode 8

Step 1:

As Bruce said, this happens when Qt tries to find xcrun when it should be looking for xcodebuild.

Open the file:

Qt_install_folder/5.7/clang_64/mkspecs/features/mac/default_pre.prf

Step 2:

Replace:

isEmpty($$list($$system(“/usr/bin/xcrun -find xcrun 2>/dev/null”))))

With:

isEmpty($$list($$system(“/usr/bin/xcrun -find xcodebuild 2>/dev/null”)))