Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

What does RunningBoard do? 5 Log insights

By: hoakley
7 August 2025 at 14:30

If RunningBoard’s copious log entries record the life cycle of apps, can we use them to our advantage? To test this out, I’ve analysed a section of log using waypoints and information provided in RunningBoard’s entries.

Waypoints, or landmarks if you prefer, are essential for navigating the log. In an ideal world we would always know when any significant event occurred, timed to the millisecond. In practice we may only be able to estimate to the nearest few seconds or minutes. Without some means of discovering exactly when to obtain log extracts, you can waste many hours trying to pin down when something happened, and in many cases will be forced to abandon the hunt.

Methods

My aim was to separate RunningBoard log entries into those handling its assertions, which should represent life-cycle events, and job descriptions giving details of apps launched. To try this yourself, open LogUI and set the Start date and time to the start of the period of interest. Set the Period to at least 100 seconds, and Max entries to 2,000 or more. Then set the Predicate popup menu to read subsystem, and type in com.apple.runningboard so that LogUI only gets entries from that subsystem. Click on the Get Log tool in the toolbar, and check you get at least 1,000 entries.

Click on the Save JSON tool to save the whole of this excerpt. To view all the RunningBoard assertions acquired over that excerpt, type acquiring assertion in the search box at the top right, and press Enter.

The window name then changes to append the text from the search box.

To save this limited selection of entries, first click on the Reduce tool to discard all the others, then click on the Save JSON tool again and save the entries using a different filename. Repeat that using each of three search terms:

  • acquiring assertion to see RunningBoard’s outline of life cycle events,
  • constructed job to see job descriptions for newly launched apps,
  • extension overlay to see similar information for appexes and similar extensions.

In my case, I analysed a period of 4 minutes of user activity on a Mac mini M4 Pro running macOS 15.6, during which there were 6,580 RunningBoard entries, suggesting that the whole log would have had well over 50,000 entries in that time, far too many to attempt any more detailed analysis. My search terms found 305 assertions acquired, 3 job descriptions constructed, and 20 extension overlays submitted.

Job descriptions

The three captured represented the three apps I had launched over those four minutes, Cormorant, DelightEd and Consolation 3. Each of them has a platform ID of 1, as notarized macOS apps. I also noticed that one was run in app translocation, although this was long after its first run. Recent versions of macOS, Sequoia in particular, appear prone to this, when an app that should have cleared quarantine gets stuck in perpetual app translocation.

Extension overlays

While I had expected to find those three app launches, I didn’t expect to see any appexes being run over this period. Those encountered consisted of three widgets, none of which had ever been opened, and five QuickLook thumbnail extensions. Most of these were run multiple times, with ScappleThumbnail appearing on six occasions. All were platform 1, except for the widgets, all three of which are bundled in macOS, for the FindMy widget and NewsToday2. They were platform 6, and subject to RunningBoard’s resource controls.

RunningBoard’s log entries here give potentially valuable insights that might otherwise be missed.

Assertions

It’s straightforward to construct a narrative of the key events that took place over that period of 4 minutes using a selection of assertions acquired. Rather than reproduce the whole of each of those waypoints, here they are laid out in more readable form.

11:40:50.424950 Acquiring assertion targeting app application.co.eclecticlight.Cormorant.10809046.10809052(501)
description "LS launch co.eclecticlight.Cormorant" ID:424-620-716
target: application.co.eclecticlight.Cormorant.10809046.10809052(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This marks the start of the launch process for Cormorant, handled in the normal way through LaunchServices and RunningBoard.

11:41:18.304367 Acquiring assertion targeting app application.co.eclecticlight.DelightEd.10206240.10206246(501)
description "LS launch co.eclecticlight.DelightEd" ID:424-620-756
target: application.co.eclecticlight.DelightEd.10206240.10206246(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This is the same for DelightEd.

11:41:20.050166 Acquiring assertion targeting [xpcservice com.apple.appkit.xpc.openAndSavePanelService([app application.co.eclecticlight.DelightEd.10206240.10206246(501) :1553])(501) 1576:1576]
description "viewBridge:1576" ID:424-391-769
target: 1576
attributes: domain:"com.apple.launchservicesd" name:"RoleViewBridge" sourceEnvironment:"(null)"

DelightEd is here being used to open a document using the openAndSavePanelService, a separate process.

11:41:44.171636 Acquiring assertion targeting app application.co.eclecticlight.Consolation3.430650.430692(501)
description "LS launch co.eclecticlight.Consolation3" ID:424-620-788
target: application.co.eclecticlight.Consolation3.430650.430692(501)
attributes: domain:"com.apple.launchservicesd" name:"LaunchRoleUserInteractive" sourceEnvironment:"(null)"

This is the launch of Consolation 3, a user error on this occasion!

Two long runs of assertions were discovered, both involving syncing the address book for Contacts.

11:41:57.462118 Acquiring assertion targeting [osservice com.apple.AddressBook.SourceSync(501):1610]
description "App is holding power assertion" ID:424-362-811
target: 1610
attributes: domain:"com.apple.appnap" name:"PowerAssertion" sourceEnvironment:"(null)", RBSAcquisitionCompletionAttribute policy:AfterApplication

The first of these was to sync the Address Book with its source in iCloud, and lasted 12.181 seconds.

11:42:11.840349 Acquiring assertion targeting [osservice com.apple.AddressBook.abd(501):1625]
description "Contacts shared filesystem lock" ID:424-1625-857
target: 1625
attributes: domain:"com.apple.common" name:"FinishTaskUninterruptable" sourceEnvironment:"(null)", RBSAcquisitionCompletionAttribute policy:AfterApplication

Shortly after that completed, synced data was updated by a service abd (Address Book Daemon?) that I had been unaware of. This only lasted 2.238 seconds.

RunningBoard’s assertions seldom appear for single-shot shell commands, and most commonly handle executable bundles rather than bare Mach-O binaries. They also don’t appear to provide clear information recording when apps are quit normally.

Conclusions

  • RunningBoard entries can readily provide accurate waypoints for many events in the log.
  • Establishing waypoints on the strength of RunningBoard log entries is straightforward in LogUI.
  • Job descriptions are readily found, and provide useful information on apps launched.
  • Extension overlays provide details of appexes that might otherwise be overlooked.
  • Acquisition of assertions identify various events in the app life cycle.
  • Once RunningBoard entries have provided precise times of events, attention can be focussed on obtaining more detail using short log extracts.

2025 年,不要再跟着小红书教程刷机了!

By: 马扶摇
31 July 2025 at 13:48

如果你看到一个人从手机店里狂奔出来,身后一个工程师紧追不舍,你会选择报警或者伸出一条腿吗?

自从小米将官方解除 BL 锁的手段限制的越来越苛刻、甚至诞生出了诸如「小米高考」之类的外号之后,一部分想要解锁刷机的用户就开发出了「拿着手机去售后网点申请系统降级、趁着工程师操作过程中抢走手机」的操作——


7 月某家小米之家的监控视频|网络

无独有偶,这样的事情并非什么新现象,其实早在小米更改解锁政策、执行 BL 解锁考试的初期,就曾有过类似的「教程」和「案例」,只是传播范围没有七月这次这么大而已。


3 月某家小米之家的监控视频|网络

与这次小米抢机事件相呼应的是,根据第一批拿到三星 Z Fold7 与 Z Flip7 的用户反应,在最新版本的 One UI 8 系统里,三星悄悄的删除了开发者选项中的「OEM 解锁」开关:

左为 One UI 5.1,右为 One UI 8

相信到这里你也感受到了,无论是像小米这种起家于制作第三方系统、依靠刷机成名的国产品牌,还是类似三星这样对于解锁刷机并不明确反对的国际大厂,都正在缩紧对于「用户解锁权限」的控制——更具体的说,是对于 BL 解锁的控制。

什么是 BL 锁

BL 的全称是 bootloader,顾名思义,它负责的是 Android 主系统启动(boot)之前的,包括驱动加载(load)和自检之类的「杂活」,你可以将它类比为 Windows 系统启动前的 UEFI(或者 BIOS)。

换句话说,BL 从原理上讲很像是汽车发动机的起动电机:汽车电池给电机供电,然后才能带动活塞点火;同样的,手机电池启动 BL,再由 BL 加载 Android 开机进程。

图|汽车之家

那么 BL 锁又是什么东西呢?

如果把 BL 比做汽车起动电机的话,BL 锁的功能相当于起动电机有了一套智能系统,会在工作前检测后面安装的发动机是否是车辆原厂。只有确认是原厂发动机,并且工况合格之后,才会啮合齿轮、开始带动点火。

至此,「BL 解锁」的含义也就不难理解了:它相当于关闭了起动电机的检测程序,只要收到启动指令就会无条件地驱动齿轮,根本不管后面连接的是原厂的发动机还是从 XJ350 上面拆下来的柴油机增大 V8 。

图|Engine Builder Magazine

而解除了 BL 锁,就意味着你获得了对发动机(Android 系统)的最高控制权——只要愿意,就可以随意更改气缸尺寸(处理器频率)、换装副厂歧管(修改默认 app)甚至是修改 ECU 数据(获取 root 权限)等等,哪怕是想要换一台发动机(刷成别的品牌的系统)也毫无压力,只要能够塞进车身(有人为你的机型做刷机包)就行。

而这种自由性,正是手机厂商对于 BL 解锁如临大敌的原因。

为什么要换发动机

智能手机的历史虽然不长,但如果说有什么东西能够在这段历史里被称为「改变生态」的话,刷机绝对算得上是其中之一。

Android 手机始于 2008 年的 HTC G1,作为谷歌对于 iPhoneOS 的回答,Android 从最开始就发出宏愿:

要和 iPhone 走一条完全不一样的开放式道路。

然而在那个软硬件结合程度远不如今天的时代,绝对的「开放性」并不见得就是好事。就像美国的西部拓荒一样,发展阶段早期的 Android 的确足够开放,也足够无法无天

图|Game Rant

彼时处理器性能不强,Android 自身的功能也不是很完善,再加上野蛮的流氓软件生态和粗陋的销售模式,让早期 Android 手机开箱即用的体验非常差劲,进而慢慢催生出了一个特殊的产业:刷机。

而对于早期的 Android 来说,刷机的确就是一项最简单的、能够让手机马上变得好用很多的操作手段。

无论是卸载运营商预装的牛皮癣应用,还是刷入更灵活的内核调度,甚至干脆换成「专为发烧而生」的新系统,都是在那个年代实际存在且紧迫的用户需求

图|小米社区 @╰☆ve佑

但就像是亚瑟·摩根在日记里写的那样:「亡命之徒与神枪手的时代即将告终」,软件野蛮生长和需要手机用户自己动手扫黑除恶的时代也最终迎来了落幕——伴随着品牌生态化和 Android 自身的完善,对于刷机的「需求」已经从改善手机的功能性逐渐便成了纯粹的爱好。

巨大的间接风险

放在今天来讲,对于这个爱好圈子以外的人来说,解锁 BL 的收益远远小于带来的风险

与十年前不同,我们今天的生活与手机的绑定程度远超我们的想象。毕竟 2015 年那会,出门没带手机还能用纸币付款呢。但是换到今天,我们的资产、支付、地址、联络、社会服务几乎 99% 要依托手机这个平台运行,上面存储的关键个人信息数量和重要性都今非昔比。

图|AlipayHK

而解除 BL 锁,就意味着手机软硬件上对于这些个人信息设置的保护手段几乎全部处在风险下。在能够借助 BL 直接修改系统内核的前提下,锁屏密码、生物识别、应用锁甚至账号锁都是可以绕开的。

更要命的是,解除 BL 锁之后会发生什么,不一定是机主本人能够控制的——

就拿最常见的丢失手机为例:如果你不小心弄丢了自己解锁 BL、刷入第三方内核、美化过系统应用、淦碎温控可以 35 度 5G 全程 120 帧畅玩原神的主力手机,又不小心被「有心人」捡到的话,他甚至不需要解开你的锁屏,就可以直接拷贝走 data 分区的所有数据。

图|Gadget Hack

你刚刚充好的几千原石丢了或许还是小事,但你不顾劝阻、毅然用系统记事本记录的各种明文账号密码,可就危险了——不需要觉得夸张,因为这就是我身边一位朋友的真实经历。

除此之外,最近你一定或多或少听过有老人去参加活动,被不认识的人以「关注公众号送鸡蛋」、「下载推广送食用油」等等借口,稀里糊涂的将自己的手机拿走之后安装后门 app,最后导致银行账户被盗、软件钱包被搬空之类的案例。

图|新华网

这些都还只是在「以第三方 app 形式安装」之后就能实现的简单操作。如果别有心机的人拿到机器,利用 BL 已经解锁的特性直接在手机系统底层植入工具,能够模拟定位、给子女发微信,模仿老人的口吻朝他们要钱,肯定有人会中招的。

这样的危险性,哪怕概率极低,也是客观存在的,而极低的发生率乘以手机的庞大基数,潜在的受害者人数依然不容小觑。虽然手机厂商会设置用 fastboot 解锁 BL 之后强制清空数据,但很难保证每个人都会在二手交易、给家里人用之前有意识手动进行 BL 回锁。

这也是我们会在近几年的 Android 手机上看到越来越多束手束脚的操作的原因之一。不管是打开 ADB 的 15 秒全屏警告,还是强制插卡激活,以及严格到离谱的 BL 解锁程序,厂商采取的限制手段是随着功能的能力逐渐升级的。

这样的做法有效吗?有效,难受也是真难受。但对于亲友被诈骗、支付宝账号被盗、信用卡盗刷这种「只要出现 1 次都是巨大损失」的风险来说,在 BL 锁的环节上有限制总比不设限制要强。

但是话又说回来,无论是粗暴的一刀切不给 BL 解锁,还是用阴阳怪气的手段强行给解锁过程使绊子,都不是负责任的办法,因为有一些霸占着渠道、行为却充满了流氓气息的软件,有时候还真的只能用 root 之类的办法才能治得住:

图|知乎 @加肥猫

如果一定要我这个用 Pixel 必然解 BL 锁、用国产手机也经常用 ADB 的弱势用户来说,索尼 Xperia 在 BL 锁上面的措施是值得所有厂商学习的——必须要用机器的 IMEI 识别码,在索尼官网上申请解锁码,然后手动在 fastboot 里一个一个敲进去才能解锁。

图|今周刊

虽然这样复古的体验多少可以被称为「解锁の仙人」,但是在保证安全性的方面是真的有用。现在你知道为什么索尼大法好了吧?

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


Last Week on My Mac: Search and you’ll find

By: hoakley
3 August 2025 at 15:00

One thing we humans are good at is searching. It’s a task we engage in from a few moments after birth until the time we slip away in death, we search everything around us. Locating and identifying that bird of prey wheeling high, finding the house keys, and that book we mislaid some time last week, meeting the perfect partner, discovering the right job, choosing the best education, looking through a Where’s Wally? or Where’s Waldo? book, and so on. Searching has transformed some into explorers like Christopher Columbus, and was the purpose of the chivalric quest. It’s what researchers in every field do, and thanks to Douglas Adams can be answered by the number 42.

Last week my searching took two new turns.

Spotlight

The first was more of a meta-search, in trying to discover more about the internals of Spotlight. Following the example of Maynard Handley, who has used them so successfully in understanding how M-series CPUs work, I looked through patents that have been awarded to Apple for the work of its search engineers. Yesterday’s slightly fuller history of Spotlight search is one result, and there are more to come in the future as I digest those patents concerned with performing search.

There’s a tinge of irony here, as many of my searches have been conducted using Google Patents, alongside Google Scholar one of the remaining search engines that doesn’t yet use AI and attempt to provide its own answers.

Logs

The other marks a new phase in my quest to get more information from the Unified log. Looking back to my first comment here, I realise how wildly over-optimistic I was when I wrote that it “should make my life a lot easier”, and that “a new version of Console will provide improved features to help us wade through logs.” Nine years later, I look wistfully at what remains of Console and realise how wrong I was on both counts.

When RunningBoard arrived in macOS Catalina, I soon noticed how “its log entries are profuse, detailed, and largely uncensored for privacy.” Since then it has proved garrulous to the point where its apparently ceaseless log chatter is a distraction, and can overwhelm attempts to read other log entries. I suspect it has contributed significantly to those advanced Mac users who now refuse to even try to make sense of the log.

One answer might be to tweak log preferences to shut out this noise, but given the purpose of RunningBoard in monitoring the life cycle of apps, why not try to use the information it provides? To do that, it’s first necessary to understand RunningBoard’s idiosyncratic language of assertions, and its protocols under which they’re acquired. The only way to do that without documentation is by observation: catalogue over 30 of those assertions for an interesting example like Apple’s Developer app, and see what they reveal.

By far the most informative entries from RunningBoard are those announcing that it’s acquiring an assertion, such as
Acquiring assertion targeting [app<application.developer.apple.wwdc-Release.9312198.9312203(501)>:2946] from originator [osservice<com.apple.uikitsystemapp(501)>:748] with description <RBSAssertionDescriptor| "com.apple.frontboard.after-life.subordinate" ID:424-748-2228 target:2946 attributes:[
<RBSDomainAttribute| domain:"com.apple.frontboard" name:"AfterLife-Subordinate" sourceEnvironment:"(null)">
]>

In a log often censored to the point of being unintelligible, this contains frank and explicit detail. The app is identified clearly, with the user ID of 501 and process ID of 2946. The originator is similarly identified as com.apple.uikitsystemapp with its PID of 748, which is confirmed in the middle digits in the Assertion ID. This is explicitly related to FrontBoard and an attribute named AfterLife-Subordinate. There’s not a single <private> to blight this entry, although further knowledge is needed to decode it fully.

Normally to get such information from a running process would require its source code to be instrumented with calls to write log entries, many of which would be lost to <private>, yet RunningBoard seems happy, for the moment, to provide that information freely. You can see what I mean by applying the predicate
subsystem == "com.apple.runningboard" AND message CONTAINS "Acquiring assertion t"
in LogUI, to obtain a running commentary on active apps and processes. Once you’ve identified a relevant assertion, you can focus attention on other log entries immediately prior to that. I will be following this up in the coming week, with fuller instructions and some demonstrations.

Although neither patents nor assertions have the significance of the number 42, in their own ways they show how the art and science of search aren’t dead yet, nor have they succumbed to AI.

Updates for file integrity (Dintch/Fintch), compression (Cormorant) and LogUI build 70

By: hoakley
14 July 2025 at 14:30

This is the last batch of ‘simple’ updates to my free apps to bring them up to the expectations of macOS 26 Tahoe. With them comes a minor update to my log browser LogUI, which is recommended for all using Tahoe, as it fixes an annoying if fundamentally cosmetic bug.

Preparing these updates for release was a little troublesome, as I attempted this using developer beta 3 of Tahoe and Xcode 26 beta 3. Little did I realise when I got all four rebuilt, tested and notarized, that this combination had stripped their shiny new Tahoe-compliant app icons. That made these new versions unusable in Sequoia and earlier, as they each displayed there with the generic app icon, despite working fine in Tahoe.

Eventually I discovered that I could build fully functional versions using Xcode 26 beta 2 in Sequoia 15.5, so that’s how they have been produced.

File integrity

Five years ago I build a suite of two apps and a command tool to enable checking the integrity of file data wherever it might be stored. This uses SHA256 hashes stored with each checked file as an extended attribute. At that time, the only alternative saved hashes to a file in the enclosing folder, which I considered to be suboptimal, as it required additional maintenance whenever files were moved or copied to another location. It made more sense to ensure that the hash travels with the file whose data integrity it verifies.

The three are Fintch, intended for use with single files and small collections, Dintch, for larger directories or whole volumes, and cintch, a command tool ideal for calling from your own scripts. As the latter has no interface beyond its options, it continues to work fine in macOS 26.

Since then other products have recognised the benefits of saving hashes as extended attributes, although some may now use SHA512 rather than SHA256 hashes. What may not be apparent is the disadvantage of that choice.

Checking the integrity of thousands of files and hundreds of GB of data is computationally intensive and takes a lot of time, even on fast M4 chips. It’s therefore essential to make that as efficient as possible. Although checksums would be much quicker than SHA256 hashes, they aren’t reliable enough to detect some changes in data. SHA algorithms have the valuable property of amplifying even small differences in data: changing a single bit in a 10 GB file results in a huge change in its SHA256 hash.

At the same time, the chances of ‘collisions’, in which two different files share the same hash, are extremely low. For SHA256, the probability that two arbitrary byte sequences share the same hash is one in 2^256, roughly one in 1.2 x 10^77. Using SHA512 changes that to one in 2^512, which is even more remote.

However, there ain’t no such thing as a free lunch, as going from SHA256 to SHA512 brings a substantial increase in the computational burden. When run on a Mac mini M4 Pro, using its internal SSD, SHA256 hashes are computed from files on disk at a speed of around 3 GB/s, but that falls to 1.8 GB/s when using SHA512 hashes instead.

dintchcheck14

Dintch provides two controls to optimise its performance: you can tune the size of its buffer to cope best with the combination of CPU and storage, and you can set it to run at one of three different QoS values. At its highest QoS, it will run preferentially on Apple silicon P cores for a best speed of 3 GB/s, while run at its lowest QoS it will be confined to the E cores for best energy economy, and a speed of around 0.6 GB/s for running long jobs unobtrusively in the background.

The two apps and cintch are mutually compatible, and with their earlier versions going back to macOS El Capitan. In more recent versions of macOS they use Apple’s CryptoKit for optimum performance.

Dintch version 1.8 is now available from here: dintch18
Fintch version 1.4 is now available from here: fintch14
and from their Product Page, from where you can also download cintch. Although they do use the auto-update mechanism, I fear that changes in WordPress locations may not allow this to work with earlier versions.

Compression/decompression

Although I recommend Keka as a general compression and decompression utility, I also have a simple little app that I use with folders and files I transfer using FileVault. This only uses AppleArchive LZFSE, and strips any quarantine extended attributes when decompressing. It’s one of my testbeds for examining core allocation in Apple silicon Macs, so has extensive controls over QoS and performance, and offers manual settings as well as three presets.

Cormorant version 1.6 is now available from here: cormorant16
and from its Product Page. Although it does use the auto-update mechanism, I fear that changes in WordPress locations may not allow this to work with version 1.5 and earlier.

LogUI

Those using this new lightweight log browser in Tahoe will have discovered that, despite SwiftUI automatically laying out its controls, their changed sizes in Tahoe makes a mess of the seconds setting for times. This new version corrects that, and should be easier to use.

LogUI version 1 build 70 is now available from here: logui170

There will now be a pause in updates for macOS Tahoe until Apple has restored backward compatibility of app icons, hopefully in the next beta-releases.

Last Week on My Mac: Plan ahead with this summer’s mallyshag

By: hoakley
29 June 2025 at 15:00

Summer is an unpredictable time of year. With the Atlantic hurricane season already upon us, we could see searing heat or devastating storms. So it is with the announcements made at WWDC earlier this month: do we have time to try out some of the new features coming in three months, or must we get on with wrangling deprecations and changes looming in macOS Tahoe?

A glance through Apple’s beta release notes might suggest it should prove innocuous, and the great majority of code that’s already happy in Sequoia should have no problems in Tahoe, and so far that’s my experience. That should leave us plenty of time to adjust our app icons so they display properly in the Dock and elsewhere, but it’s there it gets more subtly complicated.

Fix app icons

I don’t think I can over-stress the importance of using Icon Composer for creating replacement app icons. If you don’t, then Tahoe seems determined to deface many traditional icons so they become almost illegible and unusable. The only exemptions are those already conforming to the fixed outline of a square with rounded corners. Any irregularity such as putting a pixel outside that, and they’re relegated to the sin bin.

Here are two icons for the same app viewed in Tahoe. The left one uses a traditional AppIcon.icns icon image, while that on the right is the same circular PNG that has been applied using Icon Composer and added as a .icon file. So far my attempts to get this to work using Xcode 16.4 have been unsuccessful, and the only solution has been to use a beta-release of Xcode 26.

Overhaul controls

That brings with it another problem, as it automatically converts AppKit and SwiftUI layouts so they use Tahoe’s new interface style, and that can generate further work. If you look closely at Apple’s demos of Tahoe at WWDC, you may notice that its controls have changed in size and shape. Not only do most have more rounded corners, but they also have different dimensions.

Interface conversion for apps that use AppKit or SwiftUI is clever, as it preserves the original for use in previous versions of macOS, and only adopts the new style when in Tahoe. Build your app with its smart new Tahoe-compatible icon and run it in Sequoia, and it looks just the same as it did.

This demo, Mallyshag, looks the same in Sequoia, but has become a mess in Tahoe because of those changed control dimensions.

Those three buttons are significantly wider, so now overlap one another and are wider than the text box below. They need a careful overhaul before they’re ready for Tahoe. Conversion can also have unexpected side-effects: for example, I’ve had some selectable text fields changed to be editable as well. You can see an example that I missed in the left view in XProCheck’s window. I now check carefully through every detail in windows that have been migrated by Xcode to support Tahoe.

This doesn’t just apply to AppKit windows in Interface Builder. Although SwiftUI dynamically positions controls, I’ve found it necessary to increase the minimum width of some views to ensure they remain fully usable.

Aside from any code changes needed, migrating an app to Tahoe thus requires:

  • creation of a new app icon using Icon Composer;
  • adding the .icon file to the Xcode project and setting it as the app icon;
  • careful checking and rectification of all windows and their contents.

NSLog

There’s one last thing that may have escaped your attention in Apple’s release notes: NSLog. When Apple introduced the Unified log in macOS Sierra, it preserved the longstanding use of NSLog as a means of making entries with a minimum of fuss. More formal methods are more cumbersome, although they’re also more powerful, so NSLog still remains popular with developers, at least until Tahoe’s change.

A long way down the release notes, and oddly announced under the subheading of New Features, Apple states that NSLog will no longer record anything of use in its entries in the Unified log, although they’ll still be reported in full in Xcode and to stdout. One of the other purposes of my test app Mallyshag was to verify just what is now recorded by NSLog.

This is the entry obtained using LogUI when running either version of the app in macOS 15.5:

And this is the extent of entries seen in macOS 26:

So what in earlier macOS might have been a useful
Error number 1467296 in Mallyshag
is redacted to the contentless stub <private>.

If you still use NSLog, you’ll almost certainly want to move on to a better alternative, again being careful to avoid ending up with its contents redacted.

Outcomes

Come the release of macOS 26 Tahoe, there’ll be three groups of apps:

  • those that haven’t been ported at all, whose icons will be almost unrecognisable;
  • those whose icons display correctly, but with flaws in interface controls;
  • those that work as expected, with conformant icons and controls.

Some will also write dysfunctional messages in the log, because they’re still using NSLog, although few users are likely to notice that.

That doesn’t take into account those apps relying on alternatives to AppKit and SwiftUI for their interface, as those have a great deal of ground to cover in just a few months if they’re going to be ready in time for Tahoe’s release.

That’s why I’ve started unusually early in getting my apps ready for the autumn/fall. I’m sure that summer still has some surprises in store.

Mallyshag?

This is a local Isle of Wight name for a caterpillar, usually a large and hairy one. It just seemed appropriate.

merianlappet
Maria Sibylla Merian (1647–1717), Metamorphosis of the Lappet (after 1679), watercolour, 19.3 x 15.9 cm, Städelsches Kunstinstitut und Städtische Galerie, Frankfurt am Main, Germany. Wikimedia Commons.

Starting up: early kernel boot in macOS 15, iPadOS 18 and iOS 18

By: hoakley
23 June 2025 at 14:30

Starting up a Mac, iPad or iPhone begins a series of processes progressing from their small boot ROMs to user login, starting up the services required for the operating system and booting the array of hardware in the chip. Early phases, before the kernel is booted, leave little in the way of records, just a few ‘breadcrumbs’ in NVRAM, but the kernel and processes it starts write a great many entries in the log. This article describes a few of those, concentrating on macOS 15.5, with additional information on iPadOS and iOS 18.5.

Logs

These were obtained from logarchives made soon after normal startup on:

  • Mac mini M4 Pro, booting macOS 15.5 in Full Security mode from the internal SSD;
  • iPad Pro 11-inch (4th generation)(Wi-Fi), with an M2 booting iPadOS 18.5 normally;
  • iPhone 15 Pro, booting iOS 18.5 normally.

Logarchives were opened in LogUI and all log entries (excluding Signposts) were extracted for the first 5 seconds following the start of kernel boot and saved to a LogUI JSON file. Following correction for time adjustments (see below), those contained:

  • for macOS, 20,000 entries in a total of 5.7 seconds;
  • for iPadOS, 10,000 entries in a total of 5.7 seconds;
  • for iOS, 10,000 entries in a total of 5.6 seconds.

Each set of entries opens with an entry recording the first moment of the boot process, for example
08:23:33.343017 === system boot: CCB8E0AC-5B94-4789-B951-BF0B893FF45F
following which there is a gap of over 5 seconds during which preboot is completed. The next entry then records the start of kernel boot, for example in macOS with
08:23:38.536777 kprintf initialized

Periods between those two entries were 5.2 seconds for macOS, 5.3 seconds for iPadOS, and 5.1 seconds for iOS.

Times and their correction

One potential source of major error in using log entries during startup results from clock time corrections. When started up, Macs and Apple’s devices appear invariably to have clock times about 6 seconds in advance of UTC. This is corrected about 4 seconds into kernel boot, and marked in two log entries such as
00.827884 === system wallclock time adjusted
00.860742 === system wallclock time adjusted

The first adjustment normally sets the clock back slightly more than necessary, but the second corrects that more accurately.

Effects on timestamps in log entries can appear confusing, as entries prior to time adjustment are given later timestamps than entries written after the adjustments have been made. This may give the impression that the order of log entries is incorrect, and any time calculations that depend on times recorded before and after adjustment require compensation by the two adjustments made. All times given below are taken from records made before system wallclock time adjustment, thus don’t require correction.

Time adjustments may need to be taken into consideration when accessing Endpoint Security events, as some may be written before adjustments are made, so might appear to be out of kilter with later events. This could apply to boot events for the launchd Subsystem, for example.

Log entries

Shortly after the start of kernel log entries with the initialisation of kprintf, the kernel banner is written, but only in macOS
Darwin Kernel Version 24.5.0: Tue Apr 22 19:53:27 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6041

Virtual memory, logging and other fundamental features are then prepared, and in macOS (not iPadOS or iOS) TXM, the Trusted Execution Monitor, is started
TXM [Log]: build variant: txm.macosx.release.TrustedExecutionMonitor_Guarded-135.100.3
followed by the announcement of two stages of preboot, at 0.11 seconds after the start of kernel boot:
iBoot version: iBoot-11881.121.1
iBoot Stage 2 version: iBoot-11881.121.1

It’s notable that macOS gave an iBoot version of 11881.121.1, but iPadOS and iOS gave a slightly later version of 11881.122.1.

According to Apple, TXM (together with SPTM) is active on all three platforms, although it only appears to be well-reported in macOS. Apple explains: “Secure Page Table Monitor (SPTM) and Trusted Execution Monitor (TXM) on iOS, iPadOS, macOS and visionOS are designed to work together to help protect page tables for both user and kernel processes against modification, even when attackers have kernel write capabilities and can bypass control flow protections.” TXM then enforces the policies that govern code execution.

The kernel then turns its attention to loading Core Crypto support, reported in detail in all three platforms, and support for Image4 files, used extensively during and after boot:
0.295967 Darwin Image4 Extension Version 7.0.0: Tue Apr 22 19:44:19 PDT 2025; root:AppleImage4-320.100.22~1926/AppleImage4/RELEASE_ARM64E
and security policy is loaded (reported in macOS only).

AMFI and credential management

All three platforms then report loading of Apple Mobile File Integrity (AMFI), which obtains the model designator from the device tree:
AMFI: queried model name from device tree: Mac16,11
AMFI: queried model name from device tree: iPad14,3
AMFI: queried model name from device tree: iPhone16,1

which is probably the simplest way to confirm the model identifier from the log at this stage. On iOS only, AMFI next reports disabling Swift Playgrounds JIT:
AMFI: disabling Swift Playgrounds JIT services on iPhone devices

The kernel then turns to management of credentials with Credential Manager, which works with secrets managed by the Secure Enclave Processor (SEP) (all platforms). One key log entry to look for is the report of SEP Key Store startup,
"AppleSEPKeyStore":326:0: starting (BUILT: Apr 22 2025 19:45:09) ("normal" variant 🌽 , 1827.120.2)

Startup of hardware systems continues, with Bluetooth reported early, followed by IOThunderboltFamily, and the Apple Neural Engine ANE. In macOS only, the remains of an old copyright notice will then appear:
Copyright (c) 1982, 1986, 1989, 1991, 1993 The Regents of the University of California. All rights reserved.
iPadOS and iOS report Backlight startup in
AppleARMBacklight::start: Using new Backlight Architecture 1

CPU cores

After those, in macOS only, the log records registration of CPU cores and their clusters, then starts each in turn. Prior to this, all code has been run on a single core, but once the others have been started, multiple cores are available. The exact log entries recording this may vary between different M families, but typically run as follows:

  • ml_processor_register>pset_find(cluster_id=0) returned pset -1
  • ml_processor_register>pset_create(cluster_id=0) returned pset 0
  • ml_processor_register>cpu_id 0x0 cluster_id 0 cpu_number 0 is type 1
  • repeated to create each cluster and allocate CPUs to them, then
  • cpu_start() cpu: 0
  • arm_cpu_init(): cpu 0 online
  • for each CPU in turn.

Although the iPad tested has an M2 chip, no such sequence was reported for its CPU cores in the log.

Security policy

macOS reports Gatekeeper status and the start of AppleSystemPolicy:
AppleSystemPolicy GK status: enabled
AppleSystemPolicy Per file changetime scans: enabled
Security policy loaded: Apple System Policy (ASP)
AppleSystemPolicy has been successfully started

APFS

APFS follows, with differences between log entries according to platform. Initial loading is announced in each, giving the version number
apfs_module_start:3403: load: com.apple.filesystems.apfs, v2332.120.31, apfs-2332.120.31.0.2, 2025/04/22
In macOS only, NFS is announced shortly afterwards
com_apple_filesystems_nfs: successfully loaded NFS module
and handling individual file system devices follows.

Boot devices are recorded in full:
Got boot device = IOService:/AppleARMPE/arm-io@10F00000/AppleH16GFamilyIO/ans@9600000/AppleASCWrapV6
/iop-ans-nub/RTBuddy(ANS2)/RTBuddyService/AppleANS3CGv2Controller/NS_01@1/IOBlockStorageDriver
/APPLE SSD AP2048Z Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia
/AppleAPFSContainer/Macintosh HD@1
(macOS)
Got boot device = IOService:/AppleARMPE/arm-io@10F00000/AppleT811xIO/ans@77400000/AppleASCWrapV4
/iop-ans-nub/RTBuddy(ANS2)/RTBuddyService/AppleANS3CGv2Controller/NS_01@1/IOBlockStorageDriver
/APPLE SSD AP0512Z Media/IOGUIDPartitionScheme/Container@1
(iPadOS)
Got boot device = IOService:/AppleARMPE/arm-io@10F00000/AppleH16IO/ans@F9400000/AppleASCWrapV6
/iop-ans-nub/RTBuddy(ANS2)/RTBuddyService/AppleANS3CGv2Controller/NS_01@1/IOBlockStorageDriver
/APPLE SSD AP0128Z Media/IOGUIDPartitionScheme/Container@1
(iOS)

Each platform states the BSD root in a paired entry:
BSD root: disk3s1
, major 1, minor 15

By that time, the boot process is well underway and log entries are being made every few microseconds.

Key points

  • Log entry times need to be corrected when they straddle clock adjustments marked by === system wallclock time adjusted
  • === system boot: marks the start of preboot, following which there are no log entries for over 5 seconds before kernel boot starts.
  • Start of Trusted Execution Monitor (TXM) is only logged in macOS, although it’s also active in iPadOS and iOS.
  • iBoot versions may differ between macOS, and iPadOS/iOS.
  • An early log entry from AMFI reports the model designator.
  • AMFI reports disabling Swift Playgrounds JIT services on iPhones.
  • In macOS only, CPU clusters and cores are registered, and started up individually.
  • macOS then reports Gatekeeper (GK) status and the start of AppleSystemPolicy.
  • The boot device is reported in full.
  • Throughout these, many other services and hardware features are started up.
  • During early kernel boot, macOS writes 20,000 log entries in about 5.7 seconds, iPadOS and iOS 10,000.

Boot disk structure in macOS, iOS and iPadOS, and AI cryptexes

By: hoakley
20 June 2025 at 14:30

Volume structure of internal startup disks has grown increasingly complex during the transition from Intel to Apple silicon Macs. There also seems to be little information on iOS and iPadOS to compare against. This article briefly reviews structures of macOS 15 Sequoia on Apple silicon, iOS 18 and iPadOS 18.

Information for macOS is derived from the diskutil command tool, and from APFS entries in the log when booting a Mac mini M4 Pro in macOS 15.5. That for iOS is drawn from APFS entries in the log when booting an iPhone 15 Pro in iOS 18.5. That for iPadOS is drawn from APFS entries in the log when booting an iPad Pro 11-inch (4th generation)(Wi-Fi) in iPadOS 18.5. All three had Apple Intelligence enabled prior to booting. iOS and iPadOS logs were obtained from sysdiagnoses, and all logs were read using LogUI.

macOS 15 (Apple silicon)

The boot volume group consists of six volumes in a single container (partition). Two other containers are normally hidden from the user:

  • the first container of around 524 MB is reserved for preboot and secure boot support.
  • another container of about 5.4 GB is used for fallback recovery frOS, and in Big Sur was the primary recovery system, until the introduction of paired recovery volumes in macOS 12 Monterey.

The boot volume group contains:

  • System, left unmounted after booting from its Signed System Volume (SSV) snapshot;
  • Data, the only encrypted volume in the group, with numerous cryptexes grafted into it, and firmlinked to the SSV at multiple points;
  • paired, primary Recovery, containing a disk image of the Recovery system;
  • VM, the backing store for virtual memory;
  • Preboot, for early stages in the secure boot process, with cryptexes grafted into it;
  • Update, used as a working volume for macOS updates.

There are two groups of cryptexes grafted onto those volumes:

  • system cryptexes, including the large SystemCryptex or os.dmg of about 4.3 GB mainly containing dyld caches, and the smaller AppCryptex or app.dmg containing Safari and supporting components;
  • PFK volumes containing support components for Apple Intelligence features. These are numerous, and some are listed in the Appendix at the end.

If you’re wondering what a PFK volume might be, so am I. But this is what Google’s AI had to say: “Mac PFK” likely refers to a combination of MAC knives and Practical Fishkeeping (PFK) magazine. MAC knives are known for their high-quality, sharp blades and are popular among chefs and home cooks. Practical Fishkeeping is a magazine focused on fishkeeping, covering various aspects of the hobby.

These are summarised, without the help of Practical Fishkeeping, in this diagram.

iPadOS 18

In contrast to macOS since Big Sur, iPadOS and iOS only appear to have two containers (partitions) on their internal storage. The first is presumed to be similar in purpose to that in macOS, in supporting preboot and secure boot, although there is a xART volume in the boot volume group. In iPadOS, this container is smaller, at around 367 MB.

The boot volume group contains a slightly different range of volumes:

  • there is no Recovery volume;
  • there is no VM volume, as iPadOS doesn’t ordinarily support swapping/paging, although M-series models can in certain circumstances;
  • User, a second encrypted volume, appears unique to iPadOS;
  • xART and Hardware volumes are additional.

Cryptexes appear similar, with both system cryptexes and PFK volumes.

These are summarised below.

iOS 18

This is similar to iPadOS, with a first container/partition of around 351 MB, and the following differences in the boot volume group:

  • there is no User volume, and no Update volume;
  • Baseband Data is additional.

Cryptexes appear similar, with both system cryptexes and PFK volumes.

These are summarised below.

Conclusions

  • Volume structure of internal startup disks differs considerably between macOS, iPadOS and iOS.
  • As would be expected, iPadOS and iOS are most similar, but even they have substantial differences.
  • They each run their systems from a Signed System Volume firmlinked to an encrypted Data volume.
  • They each graft on two sets of cryptexes, one supplementing the system with dyld caches and Safari, the other providing components for AI.
  • There are now at least 24 cryptexes used to support AI.

I welcome corrections and explanations, please.

Appendix: Some PFK volumes from cryptexes

  • UC_FM_LANGUAGE_INSTRUCT_300M_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_300M_BAUC_FM_LANGUAGE_INSTRUCT_300M_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_DRAFTS_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_CONCISE_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAIL_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAIL_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROFESSIONAL_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_SUMMARIZATION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROOFREADING_REVIEW_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_HANDWRITING_SYNTHESIS_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MESSAGES_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_AUTONAMING_MESSAGES_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_URGENCY_CLASSIFICATION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_FRIENDLY_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_HANDWRITING_SYNTHESIS_MULTILINGUAL_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_VISUAL_IMAGE_DIFFUSION_V1_BASE_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • SECUREPKITRUSTSTOREASSETS_SECUREPKITRUSTSTORE_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAGIC_REWRITE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_IF_PLANNER_NLROUTER_BASE_EN_GENERIC_H14G_Cryptex.dmg

Source: iPadOS 18.5, configured with AI enabled for British English.

The future of SilentKnight, and updates to XProCheck and LogUI

By: hoakley
19 June 2025 at 14:30

SilentKnight’s history goes back to an unfortunate error in late 2016 when Apple shipped a batch of brand new MacBook Pros with SIP inadvertently disabled. At that time the only way to tell that was in Terminal, so I set about creating an app to make it easier to check. That became the first release of LockRattler in December 2016.

lrattlerdemo4

Demand for this grew steadily, as did LockRattler, and within a year it was checking additional security data in macOS.

sipblock2

At the same time it became clear from several reports that some Macs had EFI firmware that was woefully out of date. Some models were particularly prone to this, but at the time there were no lists of up-to-date firmware versions, and no local means to check them. In the summer of 2019, I started development on what was to become SilentKnight, originally named EFIcienC. This relied on a database that I built from looking inside macOS updaters to discover the latest firmware versions that should have been installed, but sometimes weren’t.

EFIcienC01

That soon took the familiar look of SilentKnight.

silentknight01d

Three years later, there wasn’t much that SilentKnight didn’t check for.

sk221

Since the first version of SilentKnight, Apple has steadily been putting its house in order, and Macs have undergone great change. Next year’s major version of macOS 27 will no longer support Intel Macs, and that questions whether there’s a role for SilentKnight in the future.

Much of what SilentKnight does today is rapidly becoming redundant:

  • T2 and Apple silicon firmware updates are now reliable and tied to macOS versions, so no longer need to be checked separately.
  • In Apple silicon Macs, disabling SIP requires reducing boot security, so doesn’t need to be checked separately.
  • XProtect updates are now delivered via iCloud and are more reliable, and not amenable to forced update.
  • XProtect Remediator updates have become infrequent, every month or so.
  • XProtect Remediator scans require separate, more detailed checks to interpret them properly.
  • The TCC database has changed and is no longer updated as it used to be.
  • Few security data updates are now delivered by softwareupdate.

Although SilentKnight has been a comfort over the last six years, its value is declining rapidly, and I don’t intend supporting it for macOS 27. It will though continue to support Macs running Tahoe and earlier, including all Intel models. Instead, I’d much prefer to develop Skint as a lightweight replacement for Apple silicon Macs in the future. Please provide me with your thoughts in comments here.

For those still using LockRattler, that hasn’t been updated for Sonoma or later, and the command tool companion to SilentKnight, silnite, doesn’t support Sequoia or later. They have both given good service over the years, but Macs and macOS have moved on.

XProCheck 1.7

If you use SilentKnight, you’ll be aware that XProtect Remediator scans have changed over the last year or so. Prior to that, the only time that scans by its plugins were cancelled was after an update. Now they’re run against a timer, and if they overstay their time limit, that plugin scan is cancelled. When this first started to occur, it wasn’t clear whether this was going to be a lasting behaviour, but it’s now well-established and common if not universal.

This new version of XProCheck now reports cancelled scans separately, using a ⏹ emoji rather than a warning. I have also optimised its main view to look better when running in macOS 26 Tahoe, and made its app icon compatible with Tahoe’s requirements.

XProCheck 1.7 for macOS Big Sur and later is now available from here: xprocheck17
from its Product Page, and via its auto-update mechanism.

LogUI 1.0 build 68

Although this new build of my log browser LogUI is primarily to improve compatibility with macOS 26 Tahoe, including a new conformant app icon, this may bring a pleasant surprise for those who want to browse huge log extracts. According to a presentation at this year’s WWDC, “on macOS, lists of over 100,000 items now load six times faster.”

LogUI 1.0 build 68 for macOS Sonoma and later is now available from here: logui168
and from its Product Page.

App icons

Even if you didn’t watch any of the presentations at WWDC this year, you should by now have noticed that app icons are changing for Tahoe. Please bear with me as I progressively bring mine into conformance. I will explain more, with illustrations, in my Sunday morning article here.

WWDC25 设计课程合集【中英字幕】

By: Steven
13 June 2025 at 21:40

因为想了解苹果对 Liquid Glass 的定义和执行,以及对设计和开发的建议和约束,通过这些来进一步分析这套全新的设计语言究竟意味着什么,所以在翻看官方资料的过程中也顺便就把这些视频给翻译(用 AI 辅助)了。我集中上传到了自己的B站主页,为了方便其他人,我也在 blog 这里建立一个合集页面。

这六条并不是设计相关内容的全部视频,官方课程中还有其他视频,只是这六条是我自己比较关心的部分,和我后续的视频要分析的东西相关,因此挑选了这六条。如果你有其他关心的主题,可以前往以下官方页面寻找对应的内容。

https://developer.apple.com/videos/wwdc2025/

WWDC25新设计-01|了解新的设计系统 Get to know the new design system

深入了解新的设计系统,探索视觉设计、信息架构和核心系统组件的关键变化。了解该系统如何重塑界面与内容之间的关系,让您能够创建动态、和谐且跨设备、屏幕尺寸和输入模式一致的设计。

WWDC25新设计-02|认识液态玻璃 Meet Liquid Glass

Liquid Glass 统一了 Apple 平台的设计语言,同时提供了更具活力、更富表现力的用户体验。了解 Liquid Glass 的设计原理,探索其核心的光学和物理特性,并了解它的适用场景和使用原因。

WWDC25新设计-03|从创意到界面的设计基础 Design foundations from idea to interface

优秀的应用给人以清晰、直观、使用便捷的感觉。在本课程中,您将探索应用设计如何提升功能性、传达目标、引导用户浏览内容,以及如何巧妙地运用组件,在保持简洁体验的同时又不失影响力。本课程面向各种技能水平的设计师和开发者,以及所有对设计感兴趣的人士。

WWDC25新设计-04|设计交互式片段 Design interactive snippets

代码片段是由 App Intent 调用的紧凑视图,用于显示来自您 App 的信息。现在,代码片段可以让您的 App 为 Siri、Spotlight 和快捷指令 App 带来更多功能,方法是在 Intent 中包含按钮和状态信息,从而提供额外的交互性。在本课程中,您将学习设计代码片段的最佳实践,包括布局、排版、交互和 Intent 类型的指导。

WWDC25新设计-05|迎接应用图标的新外观 Say hello to the new look of app icons

概览 iOS、iPadOS 和 macOS 的全新 app 图标外观,包括明暗色调和清晰选项。学习如何运用雾面和半透明效果,让你的 app 图标更加鲜明、动感、富有表现力,以及如何确保你的图标与镜面高光完美契合。

WWDC25新设计-06|使用 Composer 创建图标 Create icons with Icon Composer

了解如何使用 Icon Composer 为 iOS、iPadOS、macOS 和 watchOS 制作更新的 app 图标。了解如何从您选择的设计工具中导出素材,将它们添加到 Icon Composer,应用实时玻璃属性和其他效果,以及如何预览并根据不同的平台和外观模式进行调整。

LogUI build 65 introduces a Logarchive Tool

By: hoakley
11 June 2025 at 15:00

Just before the start of WWDC, I released an update to my log browser LogUI adding support for accessing logarchives. I promised that there was more support for logarchives on its way. LogUI 1.0 build 65 dedicates a whole window to them, in its Logarchive Tool.

There are many situations where you can’t access the active log, and you can’t create a logarchive using the log command tool or a sysdiagnose. These include:

  • When you only have access to the contents of the Mac or device’s storage, particularly in forensics, or following hardware failure.
  • When you want access to the logs in a backup. Time Machine backups normally include full log files, for example.
  • When you don’t have ssh or similar access to a remote Mac.
  • When the log records may be incomplete or damaged.

Provided that you can copy two folders from the hidden /var/db folder on that Mac or device, LogUI can turn those into a browsable logarchive.

Create a logarchive from folders

On your Mac, create a folder somewhere convenient such as ~/Documents. As this method doesn’t use the log command, this can be on an external disk if you wish.

From the source Data volume copy the folders at /var/db/diagnostics and /var/db/uuidtext to your folder, so it looks like this.

Open LogUI, and from its Window menu open its Logarchive Tool. This offers you four tools and two checkboxes. Click on the Create Logarchive tool and first select the folder you created, containing the log folders. Then give the new logarchive a suitable name and save it somewhere convenient.

LogUI should then inform you in its window that creation has completed. As this is performed using undocumented code for an undocumented format, it may not always work correctly. If there are any problems, repeat the same with the Debug checkbox ticked, and it will give you a detailed commentary of what it does, which should help you understand what went wrong.

Getting info about a logarchive

The trickiest part of accessing logarchives is knowing what they contain, more specifically the time periods for which they have log records. LogUI’s Logarchive window provides two aids to provide you with that information, in its Catalogue and Analyse tools.

Catalogue simply lists all the tracev3 files in the logarchive, giving the datestamps each was created and last modified, together with the period between those, and the file size.

Leave that open as you browse that logarchive, to guide your way through its entries.

Analyse goes further, in telling you about the entries in each of the persist tracev3 files in the logarchive. It tells you the most common processes that wrote the entries in each of those files, allowing you to hone in on which are of most interest. If you want to extract that information for analysis in a spreadsheet, tick the CSV checkbox and it will be shown ready to import into your favourite spreadsheet.

Finally, to save the contents of the current window as a text file, click on the Save Text tool at the right.

I have now checked LogUI’s compatibility with the first developer beta of Tahoe, and found and fixed one obscure bug in the Logarchive Tool before this new build. LogUI should now be fully compatible with macOS 14.6 and later, including Tahoe. It’s available now from here: logui165
and from its Product Page.

Enjoy!

LogUI build 60 reads iOS, iPadOS, macOS and other logarchives

By: hoakley
9 June 2025 at 14:30

Until now, LogUI has only been able to access the active log of your Mac, by reading it directly. There are occasions when you can’t do that, or want to preserve the log for future reference. You also can’t browse the log directly on any of Apple’s devices. In these cases, and others, the best solution is to make a logarchive, and browse that instead. I’m delighted to provide an update to LogUI that can browse logarchives, including those created in iOS, iPadOS, and on Apple’s other devices.

What is a logarchive?

A logarchive is an undocumented package containing copies of all the files from the active log at the moment the logarchive was created. They can be opened and browsed by Console, Consolation 3, Ulbow, the log command tool, and now by LogUI. Because they contain all the files that make up the log, they can be large, and typically range in size from about 300 MB to over 1 GB. All the files containing log entries are stored in their original binary tracev3 format, proprietary to Apple, and again undocumented, although that format has been reversed in the past.

Create a logarchive

The easiest way to create a logarchive is to run a sysdiagnose, and that’s the standard way for saving a logarchive on one of Apple’s devices. Methods vary by device, and include:

  • On a Mac, use the System Diagnostics… option in Activity Monitor’s Action tool, or press the Shift, Command, Control, Option and . keys at the same time, or run sudo sysdiagnose -f ~/Documents to save it to your Documents folder.
  • On an iPhone or iPad, press and hold both volume buttons and the side or top button at the same time, for about 2 seconds. This combination may trigger other features, though. The sysdiagnose file will be made available in Settings > Privacy & Security > Analytics & Improvements > Analytics Data, from where you can transfer it to your Mac.

Unpack the .tar.gz archive resulting from that, and you’ll find a system_logs.logarchive inside it.

On a Mac, you can instead use the log collect command to create a logarchive directly. For example,
log collect --output ~/Documents/my.logarchive --last 5m
collects the last 5 minutes of log in the specified logarchive package. macOS security will block you from trying to save that logarchive on an external volume, though.

My free log browser Ulbow uses another method for assembling logarchives, and the next build of LogUI will incorporate that and other tools for working with logarchives.

Browse a logarchive in LogUI

This new build of LogUI has a seventh tool, to Use Logarchive. Click on that and you’ll be prompted to select the logarchive to open and browse.

Because the dates and times used in the logarchive will be different from current clock time, the LogUI window displays red warning text just to the left of the Start time. Set the date and time to a period within the scope of that logarchive, and use the Get Log tool as normal.

The log excerpt shown in the screenshot above is taken from the kernel boot sequence of my iPhone 15 Pro, to demonstrate how this all works.

If you want to return that window to browsing the active log, click on the Use Logarchive tool again, but this time cancel the selection. Other windows will of course continue to browse the active log unless you set them to use a logarchive as well.

Coming soon

Although browsing saved log entries in a logarchive is exactly the same as those of the active log, dates and times can be a pain. If you want to check when log files in a logarchive were written, use the Finder’s contextual menu to show their contents, scroll to the foot of the folders inside, select the Persist folder and check the file creation dates there.

This is made even easier in the forthcoming new build of LogUI, which features a Logarchive Tool to help you navigate logarchives, and learn which date and time ranges are appropriate.

LogUI 1.0 build 60 is now available from here: logui160
and from its Product Page.

I’ll be along with a new build in a few days, once I have tested and documented its Logarchive Tool. In the meantime, I hope you’ll find LogUI useful for studying the first beta-releases of Apple’s new operating systems.

LogUI build 58 reads and writes JSON, and more

By: hoakley
5 June 2025 at 14:30

Until now, LogUI has largely been an interactive log browser, and only able to export log excerpts in Rich Text format. This new build adds three tools to greatly increase its usefulness, as it can now write log excerpts in JSON format, open saved files, and filter out unwanted log entries. To give a simple example, this screenshot shows a log extract that has been reduced to entries made only by LaunchServices, converted from JSON to CSV, and imported into Numbers.

There are three new tools in LogUI’s toolbar.

From the left:

  • Get Log fetches and displays log entries specified by the current log settings, as before.
  • Read JSON opens a dialog for you select a LogUI JSON file, and loads its log entries into the window, replacing its current contents.
  • Gloss opens the Gloss window with message text from selected log entries, enabling you to use Writing Tools and other aids, as before.
  • Reduce applies the current search to current log entries. This removes all entries that are excluded by that search, so reducing the number of log entries. If you want to keep a copy of the unreduced log, save it as a JSON file before reduction.
  • Save JSON opens a dialog for you to save the current log records to a new LogUI JSON file. This has the type co.eclecticlight.loguilog, and the extension .logui, and can be used as a regular JSON export with other apps capable of importing JSON format.
  • Save RTF saves the current log excerpt as a Rich Text Format file, using the same colour conventions, as before.

You can now filter log entries in several ways, one at a time or all together:

  • You can apply a predicate to determine which log entries are fetched in the first place, perhaps limiting them to one or two subsystems.
  • You can search for subsystems, sender or process names, or contents of messages in the search box.
  • When you have filtered the displayed log entries to those that you want, you can reduce the excerpt to include just those, and save that excerpt.
  • You can then open the saved, reduced excerpt and use further searches to navigate and analyse those entries.

As we’ve recently been discussing different types of Spotlight search, I should perhaps explain that LogUI’s search isn’t word-based, simply finds matching sequences of characters, and doesn’t support regex or wild card search. If you search for the characters arb, then it will find them in the words nearby and arbitrary, but not in arabesque.

There are two current limitations with these new JSON documents. If you double-click one, LogUI should launch automatically and will then open a new window, but won’t load that document into the window, as that part of its internal wiring isn’t yet complete. The same also happens if you try dropping a document onto the app. I did hope to have drag and drop working in this release, but the resulting code proved too complex for the Swift compiler in Xcode to negotiate, so that will also wait for a future build.

LogUI 1.0 build 58 is now available from here: logui158
and from its Product Page.

This is likely to be the last update for a couple of weeks, as I expect I’ll be immersed in WWDC and its fallout for much of the next fortnight. My outstanding tasks are:

  • complete the predicate editor in Settings;
  • add support for opening documents from the Finder;
  • add drag and drop support.

I’m also thinking about additional search/filter support, and whether a more compact binary document format might be a worthwhile alternative for large log excerpts.

As ever, I value your comments and suggestions.

Last Week on My Mac: Successful search strategies

By: hoakley
1 June 2025 at 15:00

How everything grows over time. Twenty years ago a hard disk of 100 GB was often ample, now twenty times that can be insufficient, and some have even larger media libraries. Finding files from among tens of thousands used to be straightforward, but now we’re working with millions we’re often struggling. Last week’s discussions of Spotlight search and its alternatives highlighted how important search strategies have become.

Strategy

Perhaps the most common strategy we use to search quickly and effectively is to apply a series of properties or attributes narrowing from the general to the specific: a dog, a small dog, a small grey-and-white dog, a small grey-and-white Havanese dog. In just a few adjectives we have narrowed the field to a description applying to a small number of domestic pets.

This strategy has two essential requirements: the target of your search must be included in the list of items being searched, and each of the attributes or criteria you apply in succession must include the search target. The first is obvious and critical to Spotlight’s success, and the second is the basis of how attributes are chosen. If the dog’s colour had been specified as red, then that search would have failed.

One of many skills in successful searching is judging how exclusive each criterion should be, and being more inclusive to ensure none of the criteria might inadvertently exclude the target.

Although you can combine attributes in this way when searching using the general Spotlight search window accessed through the menu bar, that’s a global search including websites and everything searchable from Wikipedia to Photos albums and Messages. When looking for a file, searching in the Finder immediately narrows the scope, and saves you wading through many irrelevant results. You can then add a search bar for each criterion, perhaps specifying that you’re looking for an image in your ~/Documents folder, each time reducing the number of hits until your choice becomes sufficiently limited.

Incremental search

Spotlight offers another technique that has become popular in search engines as their performance has improved, in what’s known as live or incremental search. As you type letters into one of its search boxes, it shows results as it gets them. This isn’t much use when entering common combinations of letters, but as they become more specific this can save time and accommodate any uncertainty you might have over spelling or the rest of the word. I use this frequently in MarsEdit when looking for old articles I have written: for example, typing wrestl will find wrestler, wrestlers, wrestling, wrestled, etc.

This works well with most languages including English, where roots and meanings are concentrated in the first parts of words, and declension and conjugation are usually found in their endings. Not all languages work like that, though, and this may not perform as well in Georgian or even German due to their morphology.

Predicates

For those who prefer to use the command line, mdfind can use predicates to express combinations of attributes, but those aren’t readily used in the same incremental way to narrow results down interactively. Another situation where predicates often come into play is when searching log entries and using the log show command, and that brings me on to LogUI, my other concern last week.

Searching the log

Let’s say you want to discover all the information RunningBoard gathers about an app, something you know is written in a log entry by the com.apple.runningboard subsystem shortly after that app starts its launch sequence. While you could search for all entries for that subsystem in the minute or so around the time you launched the app, there are likely to be thousands of hits.

To narrow down that search you have several options, including:

  • launch the app at a known time, and set that as the Start time, with a Period of just a couple of seconds;
  • set a one-off predicate to subsystem == "com.apple.launchservices" OR subsystem == "com.apple.runningboard";
  • search subsystems for com.apple.launchservices to identify the time that LaunchServices announces the app will be launched through RunningBoard;
  • search messages for constructed job description, RunningBoard’s log entry giving the details you’re looking for.

Those are ordered in increasing specificity, reducing numbers of hits, and increasing requirement for prior knowledge. That’s a general association, in that the more prior knowledge you have, the more specific you can make your criteria, and the fewer irrelevant hits you will see. As with Spotlight search, the more of these criteria you apply, the greater your chance of success, provided they all match the entry you’re looking for.

LogUI

To make LogUI more amenable to incremental search strategies, two additional features are needed. Instead of only exporting whole log extracts to Rich Text, the app needs to save and read formatted extracts. It also needs the ability to eliminate entries that don’t meet search criteria. Together those will enable use of a predicate to save an extract of reduced size, then application of search criteria, maybe saving an even smaller extract.

One way to combine multiple searches is to use multiple search bars, in a similar way to the Finder’s Find window. However, that tends to become overcomplicated, and I suspect is relatively little-used. If you do need a series of search criteria, then you also need different ways of combining them, including OR as well as AND, and that becomes a GUI predicate editor. I have yet to see any successful GUI predicate editor.

Next week, in the days prior to WWDC, I’m going to be focussing on search strategies for Spotlight, before turning to LogUI to implement these changes. This is an ideal time to let me know what you’d like to see, and how LogUI can support more successful search.

Can you trust times shown in the log?

By: hoakley
30 May 2025 at 14:30

Next to the order of entries in the log, their date and time stamps are one of the most important pieces of information they contain. In some cases, such as when you’re using the log to estimate performance, their accuracy is vital. This article reports the results from tests to validate the times given in log records provided by the log show command, and in my free log browsers LogUI and Ulbow.

Clock date and time

Dates and times given in log extracts invariably match those of the Mac’s system clock, the only catch here being adjustments for time zone and DST. The latter can become confusing if you look at the log when DST is changed, or from a different time zone. To cope with that you can use the --timezone local option in log show to express all times with uniform adjustment. Ulbow doesn’t use that, but LogUI does now synchronise all time and date stamps to the current time zone and DST.

Time differences

The log is an excellent tool for measuring time and performance, either using regular entries or Signposts that are intended for the purpose. Writing an entry into the log incurs minimal overhead, and is simple to perform from any code or script. If your favourite scripting language doesn’t give direct access to writing entries, then you can use my free command tool blowhole to do so. If you want to assess processes in macOS, then it’s usually straightforward to identify appropriate milestones that mark events and use those to calculate the period. These all depend on the times reported in log entries being sufficiently accurate.

Gold standard

Since Mac OS X, every Mac has had a high-precision internal clock within it (prior to that Time Manager could resolve times down to the microsecond but no further). This increments monotonically in ‘ticks’, an unsigned 64-bit integer, starting from an arbitrary value, and is referred to as Mach Absolute Time (MAT).

Intel Macs increment their ‘tick’ count once every nanosecond, so the difference between two readings of the clock represents the time interval in nanoseconds. Life isn’t as simple with Apple silicon Macs, as they tick three times every 125 nanoseconds, or once every 41.67 nanoseconds. Apple’s latest documentation on MAT, its units and use, comes in a Technical Q&A dated 2005.

Once correctly converted into nanoseconds, MAT is the closest available measurement of time to a gold standard.

I suspect that log entries are originally given a raw MAT as their time, and that can be made available using the log show command, or in Ulbow, as that uses log show to obtain log entries. LogUI reads the log directly, through the OSLog API in macOS, which currently doesn’t provide MAT values, instead giving a lower resolution Date value.

This validation therefore compares time intervals given by Ulbow from log entry timestamps, and those given in LogUI, against MAT intervals obtained in Ulbow. To increase the challenge, log entries used are from blowhole writing 25 log entries as fast as it can, a worst case scenario as that writes 2-3 entries each microsecond.

Comparisons

Log extracts obtained using log show in Ulbow and those estimated by LogUI were compared, and their timestamps were found to be identical.

On an Apple silicon Mac (M4 Pro), entries written by blowhole had raw MAT values that recorded intervals of 9 or 10 ticks between them, after the first three were made 73 and 15 ticks apart. From the third of the series of 25 log entries there was a strong linear relationship between recorded MAT in nanoseconds elapsed and loop number, as shown in the chart below.

The gradient of the regressed line shows that blowhole‘s log entries occurred at intervals of just under 405 nanoseconds.

Because LogUI (and regular timestamps in log show and Ulbow) only resolve to microseconds, the matching plot for LogUI’s times against loop number is stepped.

The gradient of this regression line is 0.4, indicating that the intervals occurred at 400 nanoseconds, almost identical to that found for the MAT.

Plotting times measured by LogUI (which also represents those for Ulbow and log show, as they’re identical) against that of MAT shows a good linear relationship with a gradient of just under 1.009, indicating that timestamps in log show, Ulbow and LogUI are accurate and reliable estimates of MAT.

Differences between pairs of time estimates obtained from MAT and LogUI ranged from -83 to +792 nanoseconds, with a median of +370 and quartiles of +83 to +583 nanoseconds.

Conclusion

  • Times given for log entries in LogUI, Ulbow and log show are reliable estimates of MAT to within +0.8 microseconds.
  • When nanosecond resolution is needed, the machTimestamp field from log show or Ulbow should be used, and converted into nanoseconds.

LogUI build 52 handles time zones and microseconds better

By: hoakley
27 May 2025 at 14:30

Last week’s deep dive into the precision of times in the log concluded that, with the data currently available, the highest they can aspire to are microseconds, 10^-6 seconds, and not the nanoseconds given in the last build of LogUI. The aims of this new build are to deliver correctly rounded microsecond time resolution, and to adopt consistency in time zones and DST corrections.

I described in detail yesterday how I arrived at conversion of log entry dates to yield the time in microseconds. Here I’ll consider how to treat time zones correctly.

When you enter a start time in LogUI, this is assumed to be given in the local time set on your Mac, including both its time zone and any DST correction. LogUI already takes those into account, and performs any necessary adjustments.

Now that I have completely overhauled how LogUI converts the date stored for each log entry, I have changed behaviour in comparison with the default option of the log show command, and Ulbow that accepts its timestamps without question. The best way to see that is to observe log entries when the Mac’s time zone is changed.

Ulbow, and by default the log show command, uses date and time stamps adjusted for the time zone and DST setting at the time each entry is written to the log. You should therefore be prepared to see abrupt discontinuities in its timestamps. This condensed sequence of log entries from Ulbow shows what happens when you change time zone from New York to the UK during DST:
10:50:00.729672-0400 com.apple.Settings /AppleInternal/Library/BuildRoots/ … obfuscated() obfuscate output: …
10:50:00.729687-0400 com.apple.xpc.alarm Setting timer for "com.apple. …
15:50:00.730675+0100 === system wallclock time adjusted
15:50:00.730733+0100 com.apple.mobiletimer.logging … rescheduling 0 alarms
15:50:00.730754+0100 com.apple.xpc.alarm Setting timer for "com.apple.mdmclient.timer.ManualCertRenewalCheck" in 86080 seconds.

Instead, LogUI adjusts all log entries to the current time zone for consistency in reading:
15:50:00.729672+0100 com.apple.Settings /AppleInternal/Library/BuildRoots/ … obfuscated() obfuscate output: …
15:50:00.729687+0100 com.apple.xpc.alarm Setting timer for "com.apple. …
15:50:00.730675+0100 Boundary === system wallclock time adjusted
15:50:00.730733+0100 com.apple.mobiletimer.logging … rescheduling 0 alarms
15:50:00.730754+0100 com.apple.xpc.alarm Setting timer for "com.apple.mdmclient.timer.ManualCertRenewalCheck" in 86080 seconds.

If you’re using log show, you can add the --timezone local option to adopt the same behaviour.

This also solves the dilemma when you’re browsing the log through a time zone change, for example when the clock has gone forward to DST, or the reverse. In LogUI the rule is simple: enter the current time, and all log entries will be adjusted to and shown in that single time zone.

I’ve previously explained some of the confusion that can arise with DST changes, in the autumn/fall, and again in the Spring. Hopefully LogUI won’t lead to any confusion now.

LogUI 1.0 build 52 is now available from here: logui152
and from its Product Page.

Enjoy!

Never work with children, animals or time: nailing the nanosecond

By: hoakley
26 May 2025 at 14:30

Quite unintentionally, last week became a saga about time, and a good demonstration of how you should do your utmost to avoid working with it. This all started with an irksome problem in my new log browser LogUI.

LogUI departs from my previous log browsers in accessing log entries through the macOS API added in Catalina. When it first arrived, I found it opaque, and its documentation too incomplete to support coding a competitive browser at that time. Since then I have revisited this on several occasions, and each time retreated to using the log show command to obtain log extracts. As far as time is concerned, that presents me with two alternatives: a formatted string containing a date and timestamp down to the microsecond (10^-6 second), and a Mach timestamp giving the ‘ticks’ from an arbitrary start time.

Although the latter can only give relative time, the timestamp provided suffices for most purposes, and comes already formatted as
2025-05-25 07:51:05.200099+0100
for example.

Milliseconds

When you use the macOS API, date and time don’t come formatted, but are supplied as a Date, an opaque structure that can be formatted using a DateFormatter
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSZ"
let dateString = dateFormatter.string(from: date)

to provide
2025-05-24 13:46:12.683+0100

That only gives time down to the millisecond (10^-3 second), which is inadequate for many purposes. But changing the formatting string to "yyyy-MM-dd HH:mm:ss.SSSSSSZ"
just returns
2025-05-24 13:46:12.683000+0100
with zeroed microseconds. As I can’t find any documentation that states the expected time resolution of Dates, it’s unclear whether this is a bug or feature, but either way a different approach is needed to resolve time beyond milliseconds.

Nanoseconds

The only method I can see to recover higher precision in the macOS API is using DateComponents to provide nanoseconds (10^-9 second).
Calendar.current.component(.nanosecond, from: date)
returns an integer ready to format into a string using
nanosecStr = String(format: "%09d", nanoSeconds)
to give all nine digits.

Inserting that into a formatted date is a quick and simple way to construct what we want,
2025-05-24 13:46:12.683746842+0100
down to the nanosecond.

It’s only when you come to examine more closely whether the numbers returned as nanoseconds match changes seen in Mach timestamp, that you realise they’re a fiction, and what’s given as nanoseconds is in fact microseconds with numerical decoration.

Microseconds

The answer then is to round what’s given as nanoseconds to the nearest microsecond, which then matches what’s shown in Mach timestamps
let nanoSeconds = Int((Double(Calendar.current.component(.nanosecond, from: date))/1000.0).rounded())
and that can be converted into a string using
nanosecStr = String(format: "%06d", nanoSeconds)

Rather than manually format the rest of the date and timestamp, you can splice microseconds into the @ position of the format string
"yyyy-MM-dd HH:mm:ss.@Z"
turning
2025-05-24 13:46:12.@+0100
into
2025-05-24 13:46:12.683747+0100

Unfortunately, that’s too simple. If you test that method using times, you’ll discover disconcerting anomalies arising from the fact that seconds and microseconds are rounded differently. This is reflected in a sequence such as
2025-05-24 13:46:12.994142+0100
2025-05-24 13:46:13.999865+0100
2025-05-24 13:46:13.000183+0100

where the second rounds up to the next second even though the microseconds component hasn’t yet rounded up. The only way to address that is to format all the individual components in the string using DateComponents. And that leaves a further problem: how to get the time zone in standard format like +0100?

Time zones

Current time zone is available as an opaque TimeZone structure, obtained as
TimeZone.current
Note that this doesn’t need to be obtained individually for each Date, as its components are obtained using current Calendar settings, not those at the time the Date was set in that log entry. This should have the beneficial side-effect of unifying times to the same time zone and DST setting.

But that doesn’t offer it in a format like +0100, so that has to be calculated and formatted as
let timeZone = (TimeZone.current.secondsFromGMT())/36
let tzStr = String(format: "%+05d", timeZone)

Solution

The complete solution is thus:
let timeZone = (TimeZone.current.secondsFromGMT())/36
let tzStr = String(format: "%+05d", timeZone)
let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond, from: date)
let yearStr = String(format: "%04d", dateComponents.year ?? 0)
let monthStr = String(format: "%02d", dateComponents.month ?? 0)
let dayStr = String(format: "%02d", dateComponents.day ?? 0)
let hourStr = String(format: "%02d", dateComponents.hour ?? 0)
let minuteStr = String(format: "%02d", dateComponents.minute ?? 0)
let secondStr = String(format: "%02d", dateComponents.second ?? 0)
let nanoSeconds = Int((Double(dateComponents.nanosecond ?? 0)/1000.0).rounded())
let nanosecStr = String(format: "%06d", nanoSeconds)

then concatenate those together with punctuation marks as separators to deliver the string
2025-05-24 13:46:12.683746+0100

If you’re coding in Swift, you might instead consider using Date.FormatStyle, although its documentation only refers to handling milliseconds, so I suspect that might turn out to be another wild goose chase.

If you know of a better way of handling this explicitly, don’t hesitate to let my code therapist know.

A Dance to the Music of Time in Intel and Apple silicon logs

By: hoakley
20 May 2025 at 14:30

Now we’ve got LogUI to give us the times of log entries down to the nearest nanosecond, it’s time to see whether that’s any improvement over other tools. Given that Mach Absolute Time resolves to nanoseconds (10^-9 seconds) in Intel Macs, and just under 42 nanoseconds in Apple silicon Macs, can we now resolve times of events better than when using microseconds (10^-6 seconds)?

Methods

To test this out, I used my command tool blowhole that can run a tight loop writing entries in the log as fast as possible. To do this, it uses the code
for index in 1...number {
os_log("%d", log: Blowhole.gen_log, type: type, index)
}

I then wrote loops of 20 to the log of an iMac Pro (Intel Xeon W CPU), M3 Pro and M4 Pro, and extracted the resulting log entries using LogUI with its new nanosecond times.

Results

Plotting these times against loop number resulted in unexpected patterns.

In this graph, results from the iMac Pro are shown in black, those from the M3 Pro in blue, and the M4 Pro in red. Although less well-ordered in the first to fourth loops, from the fifth loop onwards there were linear relationships between time of log entries and loop number. Linear regression equations are shown in the legend, and demonstrate:

  • on the iMac Pro each loop takes 1.0 x 10^-6 seconds, i.e. 1 μs;
  • on the M3 Pro each loop takes 5.6 x 10^-7 seconds, i.e. 0.6 μs;
  • on the M4 Pro each loop takes 4.6 x 10^-7 seconds, i.e. 0.5 μs.

which perhaps isn’t surprising.

However, the patterns of individual points are quite different. Apart from loops 4 and 5, subsequent loops on the iMac Pro are evenly spaced in time. Those on the Apple silicon chips are grouped in pairs or, for loops 14-16 on the M4 Pro, in a triplet, where two or three loops are assigned the same time in the log.

Looking at time differences, a clear pattern emerges, that log times are incremented in steps of 954 ns. For the iMac Pro, each loop occurs one step later, while for the M3 Pro and M4 Pro steps between pairs and triplets are also 954 ns. In a few cases, the step difference is slightly greater at around 1192 ns instead of 954 ns. Apple silicon chips are faster on average because each step includes two or more loops, while the iMac Pro only manages one loop per step.

Explanation

If log entry times had been given in microseconds rather than nanoseconds, the same patterns would have been seen. But without the additional precision in their times, it wouldn’t have been clear that multiple log entries were being written with identical times, down to the nanosecond.

One likely explanation is that macOS only writes log entries approximately every microsecond, and the entry time recorded for each is that of that writing. Writing log entries must occur asynchronously for the M3 Pro and M4 Pro to be able to send pairs or triplets to be written, rather than having to wait for each writing process to complete.

Thus, the time resolution of log entries is approximately 1 μs, or 954 or 1192 ns to be more precise, and that’s the same regardless of whether macOS is running on a recent Intel Mac or the latest Apple silicon chips. Although a time resolution of 1 μs is sufficient for general purposes, if you want to dig deeper, as I have done here, access to the finer resolution provided in nanosecond times is essential.

Conclusions

  • Times written in log entries are incremented every 954 or 1192 ns on both Intel and Apple silicon.
  • Faster Apple silicon chips can write more than one entry in the same time increment.
  • Although expressing the time of log entries in microseconds is sufficient for general purposes, using nanoseconds can confirm which have occurred simultaneously.

The Music of Time

So what is a Dance to the Music of Time? It’s one of Nicolas Poussin’s most brilliant paintings, that inspired a series of twelve novels written by Anthony Powell. While I wouldn’t attempt to summarise those, here’s the painting to enjoy.

poussindancemusictime
Nicolas Poussin (1594–1665), A Dance to the Music of Time (c 1634-6), oil on canvas, 82.5 × 104 cm, The Wallace Collection, London. Wikimedia Commons.

Poussin’s Dance to the Music of Time (c 1634-6) shows four young people dancing, who are currently believed to be Poverty (male at the back, facing away), Labour (closest to Time and looking at him), Wealth (in golden skirt and sandals, also looking at Time), and Pleasure (blue and red clothes) who fixes the viewer with a very knowing smile. Opposite Pleasure is a small herm of Janus, whose two faces look to the past and the future. Father Time at the right is playing his lyre to provide the music, and an infant seated by him holds a sandglass, to measure time periods. Above them in the heavens, Aurora (goddess of the dawn) precedes Apollo’s sun chariot, on which the large ring represents the Zodiac, thus the passage of the months. Behind the chariot are the Horai, the four seasons of the year.

Resolve time better in LogUI build 48

By: hoakley
19 May 2025 at 14:30

Macs keep time exceedingly precisely, although there are important differences here between Intel and Apple silicon models. Their most precise record of time is given in Mach Absolute Time (MAT), the number of ‘ticks’ since an arbitrary start. In Intel Macs, each tick occurs every nanosecond (10^-9 second), providing high resolution, but ticks are less frequent in Apple silicon chips, occurring once every 41.666… nanoseconds instead.

You can test this on an Apple silicon Mac using my free utility Mints, which has a convenient button to display Mach timebase information. Run Mints in native mode, the default as it’s a Universal App, and it reports the Arm values; force it to launch as an app translated by Rosetta, and it will give the same timebase as an Intel Mac.

time01

time02

Although entries in the log are recorded in MAT’s high resolution, most methods of accessing log entries lose much of that precision. The datestamps provided by the log show command, for example, round time to the nearest microsecond (10^-6 second), although it’s capable of delivering a field in MAT’s nanoseconds. The bundled Console app is similar, but lacks any option to display MAT. My Ulbow app can display both datestamps with microseconds and MAT, but until now LogUI has been limited to displaying only time in milliseconds (10^-3 second).

To put these into context, in each microsecond the P core in the CPU of an M4 chip can complete execution of over 1,000 instructions, and in a millisecond that becomes more than a million instructions.

LogUI has been constrained by the formatted output available using Date and DateFormatter in the macOS API, which appear to be incapable of generating time any more precisely than milliseconds. After several earlier unsuccessful attempts, I’m now able to obtain time in nanoseconds, using Calendar and DateComponents in the API. For example, to obtain a formatted string containing the nanosecond component of a Date variable named date:
let nanoSeconds = Calendar.current.component(.nanosecond, from: date)
let nsTime = String(format: "%09d", nanoSeconds)

The string nsTime can then be spliced into a formatted date string.

I have incorporated this into a new build of LogUI, which also has extended information about the log display in its Help book. LogUI 1.0 build 48 is now available from here: logui148
and from its Product Page.

Tomorrow I’ll consider whether these more precise times are of use, and what we can learn from them.

Use Writing Tools to understand the log in LogUI build 46

By: hoakley
12 May 2025 at 14:30

I’ll be the first to admit that I’m sceptical of AI, and seldom use ChatGPT or Writing Tools. One of the conditions imposed by the magazines that I write for is that none of my contributions use AI in any way, either to research topics or to manipulate the text. Besides, I’d far rather all the mistakes I make are mine, and not introduced by AI. But I am impressed by Writing Tools, and think you might find them useful when trying to extract information from and understand the log, when using LogUI.

I’m therefore delighted to announce a new build of LogUI that gives access to summarisation features in Writing Tools to analyse and clarify log entries.

Most obviously, this build reworks the interface by promoting the button commands to its toolbar. From the left, these are:

  • Get log extract (circular arrows).
  • Gloss (magnifying glass on document page).
  • Save as Rich Text (downward arrow and box).

Following those is the popup menu to select the field to be used for search, and at the right end the Search box itself.

A more subtle change is aimed at making it less confusing when using multiple windows and search criteria on log extracts from the same time. The title shown in each window now appends any search term in use. That’s shown in the window, and in the Window menu, but isn’t included in the default file name if you save the extract in Rich Text.

Currently, LogUI supports two ways of moving log extracts to other apps: you can save the whole extract as a formatted Rich Text file, or copy the most important fields in selected entries as text. Build 46 adds a third as the bridge to Writing Tools, in what I term a gloss. This is generally used for words added to a text, either in between its lines or in the margin, that explain words in the main body of that text, and can be gathered together in a glossary. In LogUI this functions as a special pasteboard and plain text editor, the Gloss window.

The message field of some log entries is very large, containing a lot of information some of which may be of importance. The example I use here gives the registration details of an app being launched through RunningBoard. To copy those into a Gloss, select that log entry and click on the Gloss button in the toolbar. The contents of the selected message field(s) are then displayed in the Gloss window, a basic text editor, where you can manually format them if you wish, copy and paste the contents into a text document in another app. This works fully on all Macs running macOS 14.6 or later.

As this window contains a SwiftUI TextEditor view, you can also use Writing Tools on any selection you make within its text (Apple silicon Macs only). Select all using Command-A, hover the pointer over the selected text and you’ll see the Writing Tools blue button appear to the left of the window. Click on that, or use the contextual menu on the selected text, and you can now apply any of those Writing Tools to the contents.

If you try to use a Writing Tool that can’t cope with the text contents, you’ll see the error Writing Tools Unavailable.

In that case, open the contextual menu and try a different tool that can cope. Some log messages don’t contain much English, and in those cases Writing Tools might try another language such as German before reporting that the language isn’t recognised or supported.

Text in that Gloss window persists, and is saved into LogUI’s preferences. Only one Gloss window is available, and it contains the text from those entries selected the last time you clicked on the Gloss button. When you do that, the new gloss replaces the old. If you want to save the previous gloss, copy and paste it before clicking on the Gloss button.

Writing Tools can’t interpret log entries or diagnose problems from the log, but its summaries can make complex lists more comprehensible, and sometimes provide additional information that can be helpful. Always check its output against the original, as it can make mistakes.

To illustrate how this might help, here are examples taken from an original RunningBoard registration for the Pages app, starting
'app<application.com.apple.iWork.Pages.6871230.6871236(501)>' Constructed job description:
<dictionary: 0x910d117a0> { count = 23, transaction: 0, voucher = 0x0, contents =
"Platform" => <int64: 0x94ab1b6b9872cd77>: 1
"ProcessType" => <string: 0x910c2dc20> { length = 3, contents = "App" }
"EnableTransactions" => <bool: 0x1fb02aba0>: false

and running on for many more lines after those.

Writing Tools’ Summary reads:
The job description for the Pages application is provided. It includes details about the platform, process type, environment variables, and more. The description also specifies the program arguments and the path to the Pages executable.

Key Points start:

  • Application Name: com.apple.iWork.Pages
  • Application Bundle Identifier: com.apple.iWork.Pages
  • Application Platform: 1
  • Session Types: “Aqua”, “LoginWindow”
  • Initial Task Role: 2
  • Environment Variables: Includes variables like `__CF_USER_TEXT_ENCODING`, `TMPDIR`, `SHELL`, `HOME`, `SSH_AUTH_SOCK`, `LOGNAME`.
  • User Information: USER: hoakley, HOME: /Users/hoakley

List starts:

  • The job description is for a constructed application.
  • The application is identified as ‘app<application.com.apple.iWork.Pages.6871230.6871236(501)>’.
  • The application is running on a platform with an ID of 1.
  • The process type is “App”.
  • Transactions are not enabled for the application.
  • The application is managed by “com.apple.runningboard”.
  • The bundle identifier for the application is “com.apple.iWork.Pages”.
  • The application is part of a resource coalition with an ID of “app<application.com.apple.iWork.Pages.6871230.6871236(501)>”.
  • Pointer authentication is disabled for the application.

I think the first item there is a minor misreading, as I would understand that the text reports that a job description has been constructed for the application, not that the application is somehow constructed. However, other items listed appear to be faithful to the contents of the original message.

In some cases I have seen Writing Tools spell out an abbreviation, and in most it lays out the contents of long lists and dictionaries more accessibly. Try it out and see what you think.

LogUI 1.0 build 46 is now available from here: logui146
and from its Product Page.

Enjoy!

Last Week on My Mac: Who’s afraid of changing interface?

By: hoakley
11 May 2025 at 15:00

With Apple’s annual Worldwide Developers Conference less than a month away, speculation about what’s coming in macOS 16 is starting to warm up. So far that has concentrated on increasing consistency in interfaces across the different platforms, which could mean almost anything. As far as macOS is concerned, that’s largely up to AppKit and SwiftUI, its two major interface libraries.

AppKit remains widely used, and is still the more complete of the two. Descended from the UI framework in NeXTSTEP, it was in the core of Mac OS X at the start, and has been the mainstay for the Finder and Apple’s own apps for the last 25 years. It has a close relative in UIKit for iOS and iPadOS, although they are less comprehensive in their features.

SwiftUI is an interesting experience for the macOS developer, and is currently an archipelago of delights in a sea of disappointment. Some of its features are powerful, but a great deal is still lacking. Support for views and features widely used in modern iOS and iPadOS apps is impressive, and it opens up features such as the List View that I praised recently. But when it comes to essentials that are confined to macOS, such as menus, a great deal of work remains as it comes up to its sixth birthday on 3 June.

This is demonstrated in one of the best tutorials I’ve seen on using SwiftUI for macOS, in this case to develop a Markdown editor, written by Sam Rowlands of Ohanaware. No sooner has he set up a split view to accommodate both the Markdown source and its preview in the same window, than he writes: “The TextEditor in SwiftUI ticks the box of offering a way to edit a large volume of text, but that’s about all it does. Apple have a much more powerful text editor already in the macOS as part of their AppKit framework, so we’re going to wrap that instead.”

This was my experience a while ago when I looked at a range of document formats. Open the Help book in LogUI and what you see there is cast not in SwiftUI, which still doesn’t offer a PDF view, but reaches back to AppKit. While creating a useful Rich Text editor using AppKit is amazingly quick and simple, even plain text editing in SwiftUI is feeble. There are plenty of experts who will advise you “SwiftUI’s text editor is very limited. It doesn’t support much more than entering large amounts of plain text. If you want rich text editing, you will have to use either NSTextView or UITextView.”

These are fundamental features that should by now be easy going for any macOS interface library that’s six years old.

Continuing dependence on both AppKit and SwiftUI presents Apple with the problem of having to update both to reflect changes it intends making to improve interface consistency, then for iOS there’s also UIKit. Not only that, but all three libraries have to integrate and work together.

SwiftUI has undergone constant change over those six years. One of its most substantial changes has been the move from the Observable Object protocol to the Observable macro. Apple describes how to migrate in this article, complete with sample code. But that poses the developer a problem, as adopting the latter is only possible in apps written for macOS 14 or iOS 17 or later. That’s why LogUI requires a minimum of macOS 14.6, as do many of the better SwiftUI apps. Writing SwiftUI apps to support macOS older than Sonoma and Sequoia is thus a serious undertaking, and whatever macOS 16 and its new version of SwiftUI bring, you can be sure they’ll make backward compatibility even more impractical.

Documentation for SwiftUI is also broken. Apple seems to have stopped writing conceptual explanations about ten years ago, and structured guides have been replaced by terse and usually uninformative references to individual functions and other details of the macOS API. The only way to try to gain understanding of SwiftUI is to turn to third-parties, who are more interested in the lucrative iOS market rather than macOS, and think a series of example projects are a substitute for a systematic guide.

If there’s one sound investment for the future that Apple could make from its much-vaunted half trillion dollar investment in the US, it would be to hire a large team of technical authors and catch up with its ten-year backlog of documentation.

Whether you gasp with horror or delight when Apple reveals what’s coming in macOS 16 next month, spare a thought for all the changes that have to take place in AppKit, UIKit and SwiftUI, all the documentation that won’t get written, and how code is going to struggle to be compatible with macOS 16 and Sequoia or earlier. Then for good measure throw in the inevitable load of new bugs. So you still want to beta-test macOS 16?

预言在应验:五年前所讨论的未来人机交互的新范式_6.ylog

By: Steven
16 June 2024 at 22:58

从 2024 年的今天,回望 2019 年的 Apple 和 Ive 团队,我们会发现有些变化和趋势似乎是早已注定的。在过往的观察和分析中,我们所预言的事情正在成为现实和主流。常言道以史为镜可以知兴替,今天再看当时的 Apple 和 Ive 团队,关于产品的演进思路和设计策略的变化都早有端倪,也能预见在 AI 席卷的浪潮下,Apple 将会如何应对。

在这一期,你会听到:

—- 二十年前的专利文件:通体透光的 iPhone

—- 国产厂商和 Apple 在设计上的差异

—- 成功的设计:AirPods 只是剪掉线的 EarPods

—- 塑料手机的设计巅峰:iPhone 5c

—- 刘海与机器视觉:早早布局的 AI 伏笔

—- 未来十年的人机交互:人和人之间怎么交互?

—- 设计策略上的「S型曲线」体现在哪里?

—- 产品路径上迷路的 iPad

—- 光洁的划痕:是矫情还是哲学?

—- 史上最佳手机壳:iPhone 5c 的多彩硅胶壳

—- 拟物化的残党,现在理解扁平化的先进性了吗?

|相关图片|

首款 Unibody 设计于 2008 年 10 月发布
截图来自:Designed by Apple in California

查看更多图片和设计讨论:Mac Pro 2019

|拓展阅读|

如何评价 iPhone X 的工业设计?

交互的王,时代的狂!万字详解灵动岛的今生来世!

十年轮回?经典进化!工业设计师深入解读 iPhone12!

从技术寿命 S 曲线,看阳极氧化铝的设计

抽象的产品,用户「界面」的设计

如何看待 Evans Hankey 从 Apple 设计团队离职?

注定会离职的 Jonathan Ive 和科技产品的设计趋势

|登场人物|

苏志斌:工业设计师,车联网智能硬件产品经理 / 联创,《设以观复》作者

王汉洋:AI 行业从业者,多档播客主播,《拯救东北1910》《山有虎》作者

|相关链接|

若你所使用的播客客户端未能完整显示插图,或遇网络问题未能正常播放,请访问:

荒野楼阁 WildloG 的地址:https://suithink.me/zlink/podcast/

阅读设计相关的各类文章:https://suithink.me/zlink/idea/

|其他社交网络媒体|

苏志斌 @ 知乎|SUiTHiNK @ 即刻 / 微博

苏志斌SUiTHiNK @ Bilibili / YouTube / 小红书

|联络邮箱|

suithink.su@gmail.com

欢迎在 小宇宙、Spotify、YouTube、Apple Podcast 收听本节目,期待你的留言。

面向产品设计的 Web 前端分享会(分享会记录)

最近听说部门里面的产品或本地化运营对 Web 前端相关的内容比较感兴趣,正好我有相关的实践经验,所以在公司做了一个 Web 前端相关的分享会。分享内容包含:

  1. 使用 Devtools:介绍 Chrome 浏览器内的模拟、编辑和审查工具;
  2. 网页和部署:介绍 HTML, CSS, JavaScript, React,以及网站的部署和托管;
  3. 网页性能指标:介绍网页性能常用指标和测量工具;
  4. 资源分享:分享浏览器插件、网站和课程推荐。

与以往不同的是,这次分享会中加入了互动环节。我做了一个代码 Playground,尝试帮助观众了解 React,以及 React Props 的概念,并留了两个小任务,给观众尝试去实践对 React 项目进行编码。

完整的分享内容内容请继续浏览本文。

使用 Devtools

这个章节主要介绍 Chrome Devtools 一些可能不为人知的功能,来帮助我们提高日常工作中的效率和解决一些问题。先介绍 Devtool 里面「模拟」相关的功能。

模拟设备和屏幕尺寸

在 Devtool 里打开设备工具栏,在这里除了能够自由调整网页宽高,还能够模拟各种主流设备的屏幕。

甚至还能读取到网页里面的断点样式,提供快捷切换各种断点的方式。

需要注意的是,这里模拟的设备是会带上 UA 的,所以如果想在电脑里调试一些做了移动端特化处理的网站(比如访问主域名时,判断到是手机设备,则会跳到移动端的专门网站),是需要用到这个功能的。

模拟伪类

Devtools 还可以帮助我们排查各种交互状态下的样式问题,最常用的是,比如说我们想仔细排查某个元素的悬停和按下状态的样式,则可以在选中元素之后,勾选对应的伪类选项。

模拟媒体

在渲染面板(需要手动开启,浏览器默认是没有打开这个面板的)能够模拟部分系统设置,比如亮暗模式、打印模式、高对比度和减少动态效果等。

与之对应地,可以扩展一个概念叫做 CSS 的媒体查询,CSS 还可以探测到很多用户设备的属性或者设置,比如设备指针精度、视窗比例、当前是否全屏模式、设备方向等…

能探测的内容很多,但实际能用起来的可能只有寥寥数个,最全面的信息可以取 MDN 上查看。

编辑网页文字样式

Devtools 还提供了一个新的字体编辑器,能够让我们实时更改网页中的字体家族、字体大小、字重等属性。

编辑网页内容

我们在 Devtools 控制台里面执行代码document.designMode = 'on' 后,就可以实时在本地修改网页文字内容了,就跟平常打字一样。很适合用在测试文案长度的场景。最后也会分享一个浏览器插件,能够对网页做更多的编辑。

审查 React 组件

最后介绍一个审查 React 组件的方法,有时候我们想看某个元素是不是用的组件库,或者这个组件包含了什么属性之类的,可以下载 React Developer Tools,然后点选网页中的任意元素,进行审查。

网页和部署

接下来我介绍一下网页构成和网站部署相关的内容。

通常来说,HTML, CSS, JavaScript 是构成网站的三个要素。其中:

  • HTML 用来用于定义网页的结构和内容,可以用来创建网站的各个部分,比如标题、段落、图片、链接等。
  • CSS 用来定义网页的样式和布局,这个可能会是咱们设计师比较熟悉的部分,我们能够利用 CSS 来定义 HTML 元素的各种样式,控制它们的布局和位置。
  • JavaScript 用来实现各种功能逻辑和操作交互。比如响应点击事件、动态修改网页内容,根据条件执行动画效果或展示特定内容等。

CSS 预处理器

上述的三种语言,都有各自对应的语法规则。而 CSS 预处理器,则改进了原有的 CSS 语法,使我们能使用更复杂的逻辑语法,比如使用变量、代码嵌套和继承等。

简单来说,CSS 预处理器能让我们写样式代码的过程更顺畅,使代码有更良好的可读性和扩展性,帮助我们更好地维护代码。

举个简单的例子,比如原本的 CSS 语法中要求我们给每一个元素写样式时,必须以花括号开始和结尾,而且每一条样式规则直接都要以分号隔开,而 Stylus 则能够让我们跳出这个限制。直接用换行和缩进来代替。

CSS 框架

另一个值得一提的概念是 CSS 框架。CSS 框架则提供了一套预设样式,比如颜色板、字体梯度,布局和断点设定等;以及一些常用组件,如导航栏、对话框和页脚等。

简单来说,就是提供了一批开箱即用的样式,便于开发者快速启动项目,同时也会保留高度自定义的空间,用于支持各种各样的需求。通常 CSS 框架都会包含使用某个 CSS 预处理器,甚至内置了一些图标库,主打一个 “开箱即用”。

这里稍微介绍一下一个 CSS 框架:Tailwind CSS。是一个高度定制化的 CSS 框架,通过大量的预定义类名,使开发人员快速构建和设计网页界面。

与其他 CSS 框架相比,有一个显著的特点是 Tailwind CSS 本身不会包装一个组件出来,比如按钮、输入框的样式,没有预设好的。取而代之的是,Tailwind CSS 将各种原子级的 CSS 类名包装起来,比如:

  • 设置左右两边的 Padding,用 px-[...] 类名来实现;
  • 设置一个元素为块级元素, 用block 类名来实现…

如果想要在 TailwindCSS 中,使用打包好的组件,达到开箱即用的效果,可以通过各种官方/非官方的模版或组件生态来进行。比如:

React

接下来介绍另一个概念:React。这是一个用于构建 Web 和原生交互界面的库(是的,它能够用来做 App,不仅仅是网页)。而且引入了 JSX 语法,将 HTML 和 JS 结合起来,以一种更直观和易于理解的方式描述界面的结构和内容。

React 有一点和我们的设计稿很像,就是它的组件思维。在构建用户界面时,React 主张先把内容分解成一个个可以复用的组件(把具体的交互、功能逻辑写在组件里面)。然后在页面中将各个组件连接起来,使数据流经它们。

下图引用了官网中的一个例子,其中:

  1. 完整的应用,可以理解为由多个组件拼接成的完成网页;
  2. 搜索组件,用来获取用户输入;
  3. 数据列表,会根据用户搜索来过滤和展示内容;
  4. 每个列表的表头;
  5. 表格内每条数据。

现在我们用一个具体例子来简单介绍下 React 的组件。

在上图中,展示了一个页面页面 App.jsx 包含了 Profile、Gallery 和 FAQ 组件,以及 Profile.jsx 组件的代码。右侧是输出页面,展示了三个组件拼接而成的页面效果示意图,其中 Profile 组件模块里展示的内容,是和 Profile.jsx 文件内代码一一对应的。

上述的组件只是将一个模块包装起来,使其能够被其他地方复用。但组件内容是固定的。接下来会为大家展示如何向组件传递 Props,实现上文提到的一句话 “使数据流经他们” 。

在上图中,我们先将一些 Props 传递给组件 Profile(比如这里传递了图片的地址、人物姓名和描述),然后在 Profile 组件内接收这些 Props,并在组件代码内使用这些数据。

现在,我们就做出了一个可以复用的组件了,可以根据不同的内容来展示相关的人物信息。

大家有没有觉得这种做法有点熟悉?是的,在 Figma 中,我们的组件里面也有类似的做法。Figma 组件同样同样传递字符串、布尔和组件等内容。

实际上 React 组件可以传递的参数不仅仅只是上面例子中的字符串和布尔值,还能传递数值、函数、对象、Node 类型甚至另一个组件等。

我做了一个简单的 Playground,提前封装好了一个 Profile 组件,会传递一些字符串、布尔值(是否展示网站标签)以及数值(圆角大小),帮助大家更好地理解。

🛝 Playground

我做了一个 🛝 Playground ,大家可以在里面看到这个组件的具体的情况,实际看一遍代码可能会帮助理解 React 的组建和 Props 概念。

同时我也写了两个小任务给到大家去尝试,大家可以在上面的编辑器中自由尝试。

发布网站

到了这里,相信大家对构建一个网站已经有了初步的认识,接下来我为大家介绍下如何将构建好的网站发布的互联网当中,能够真正地被世界各地的人们浏览。

方法一:部署到服务器

这是比较传统的方法,先将项目相关的文件放进服务器里面(比如阿里云 ECS,或轻量服务器等)。然后在服务器内安装 NGINX,索引到项目文件夹,定义好首页、端口、404 等场景,最后将域名解析到服务器 IP。之后我们的网站就能在互联网上被人们访问了。

方法二:托管到服务商

这种是相对省心的方法,将我们项目所在的 GitHub 仓库,链接到服务商的托管服务当中。等于是由服务商来帮我们部署、发布项目,不用自己来配置服务器的各种内容了。下图列举了几种常见的网站托管服务商,分别是:Vercel,Github Pages 和 Netlify。

以 Vercel 来举例,除了能够托管网站之外,对每一次发布进行管理,甚至能够是对不同代码分支进行独立发布,还能收集网站访问数据等。

网页性能

接下来为大家介绍网页性能相关的内容。通常一个网站性能好不好,我们能够在体验时主观地感受到,比如打开时很慢、滚动时卡顿,或者点击按钮后很久才响应等等。但如果要准确地判断到网页的性能到底如何,是需要依赖具体指标的。

下面介绍三个常用的指标,分别是:FCP(首次内容绘制)、LCP(最大内容绘制)以及 CLS(积累布局偏移)。

FCP(首次内容绘制)

FCP 是一个关键指标,用来测量页面从开始加载到第一个页面内容在屏幕上完成渲染的时间。越快的 FCP 时间能够让用户感知到网页有在正常运行,而不是停滞、无响应。

这里提到的 “内容” ,指的是文本、图像(包括背景图像)、<svg>元素或非白色的<canvas>元素。如下图所示,FCP 出现在第二帧。

LCP(最大内容绘制)

LCP 指的从页面开始加载到可视区域内可见的「最大图像」或「文本块」完成渲染的时间。

这里提到的「最大图像」或「文本块」,具体来说是包含<img>元素、内嵌在<svg>元素内的<image>元素、块级文本等。

而测量方式,则是在页面加载过程中,记录视窗内的元素的渲染大小,取尺寸最大的元素,回溯这个元素被完整渲染的时间。注意,如果元素的有一部分在视窗外,在视窗外的部分不会参与到尺寸比较当中。

如下图所示,LCP 发生在第二帧,因为这个时候渲染尺寸最大的文本块被渲染出来了。后续帧当中,可能渲染出了一些图片,但尺寸都比文本块小,所以文本块依然是这个视窗内的最大元素。

CLS(积累布局偏移)

CLS 是指可视区域内发生的最大布局偏移分数。简单来说就是测量页面在加载时,元素的位置出现意外的偏移情况,如果元素尺寸大,而且位置偏移比较远,那么 CLS 分数就会显著增高。

这个指标会跟实际的用户操作或者体验有直接相关,所以应该也会是咱们设计师需要重点关注的内容,因为有时候布局偏移,是会比较影响用户获取信息、或者进行操作,甚至引发一些不可挽回的损失。

然后我来介绍一下测量网页性能的工具吧。我自己用过这两个,发现其实没啥差别,大家看喜好使用即可:

两个工具都能模拟桌面设备或者移动设备,记录多项关键指标的数据,并给出改进建议。

观察页面性能情况,不仅仅是前端技术人员要做的事情,了解到设计师也是可以参与到其中的。

比如 Guillaume Granger,他会比较想控制页面中 JavaScript 的数量,所以它提到,他会将所有用了 JavaScript 相关信息记录在表格当中。之后每次在网页中使用 JavaScript 时,都会跟之前的记录进行比对,判断重要性,决定是否在这个位置上使用 JavaScript。

开发者 Thomas Kelly 则提出了当意识到页面性能出现瓶颈时,需要做的事情,比如:

  • 制定一个目标,团队一起往这个目标前进;
  • 高频收集页面性能数据;
  • 尝试用不同方式来解决同一个问题;
  • 与同伴分享对性能的一些新发现…

资源分享

最后来分享一下相关的资源吧,包含两个插件、三个学习网站以及一个 React 课程。

插件:VisBug

介绍一个谷歌官方出品的插件:VisBug,主要用来帮助用户在浏览网页时进行调试和设计,包括编辑和可视化页面的 CSS,尺寸和字体等元素。

插件:Motion DevTools

Motion DevTools 是一个检查网页动效的插件,可视化和分析用户交互设计中的滚动、动画效果,并支持实时编辑、预览或导出等功能。

网站推荐

接下来介绍三个在国内外拥有较高知名度和影响力的设计师和开发人员。他们的观点、经验分享往往能给我带来一些新的启发。尤其是他们对钻研新技术的热情,是非常强烈的。

课程推荐

最后强烈推荐一门 React 课程——The Joy of React,这个课程我在年初的文章也有提到过,是以互动式课程的形式,由浅入深地讲解 React。从基础的组件 props 和 JSX 知识,到 Hooks、API 设计等等,讲述非常清晰,强烈推荐。

分享会感想

分享完之后感觉效果可能还不错,大家都有各自的收获。而且分享会中也不时有人提出相关问题,我也一一进行解答了。

或者也有对我分享内容的一些补充,比如我在分享完 Devtools 环节的时候,有同事也分享了一个在 Application — Cookie 面板里快速切换网页语言的方法。

后面了解到大家对于 CSS 和 React 那块听的比较迷糊,因为原本没有实践过的话,会对这些没有什么概念。而且大家好像对 🛝Playground 没有什么兴趣,并没有人对里面的内容有什么提问和看法之类的,可能到这一步都比较迷糊?🤔

指标那块倒是有不少同事关心,问了几个问题,比如有哪些方法来去改进几个指标的数据,或者在设计过程中是否可以提前避免性能问题等等。

总体来说和之前的分享会相比,这次分享会的参与度比较不错。

MIUI稳定版12.0直升12.5开发版方法

By: fengooge
27 March 2021 at 11:30
从网络反馈来看,最新的 MIUI 12.5 无论是在系统流畅性上还是隐私保护上,都有非常明显的提升,我在升级之后的第一感受就是系统真的很流畅,比我上一个 MIUI 12.0.7 稳定版有非常大的提升。MIUI 12.5 虽然是测试版系统,但是稳定性和完成度上都很高,推荐大家都升级。关于 MIUI 12.5 的官方介绍页面:https://home.miui.com/MIUI 测试版系统的常规升级方法,是需要去官方申请内测或公测名额。但是现在官方内测和公测通道都已经关闭,想借用别人已经有权限的小米账号,又有隐私泄露的风险。这里就介绍一个非常规方法,也被很多人戏称为替换安装包的「偷渡法」。【方法及步骤简介】1、下载好可以升级的 MIUI 12.5 内测版安装包(A包);这是小米官方 MIUI 安装包的 GitHub 下载页面:https://github.com/mooseIre/

❌
❌