<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iOS &#8211; 编程技术记录</title>
	<atom:link href="https://blog.z6z8.cn/category/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ios/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.z6z8.cn</link>
	<description>世界你好!</description>
	<lastBuildDate>Fri, 23 Jan 2026 10:23:31 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>Undefined symbols &#8230; dispatch thunk</title>
		<link>https://blog.z6z8.cn/2026/01/23/undefined-symbols-dispatch-thunk/</link>
					<comments>https://blog.z6z8.cn/2026/01/23/undefined-symbols-dispatch-thunk/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Fri, 23 Jan 2026 10:23:02 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1527</guid>

					<description><![CDATA[一个因为swift name mangled符号不一致导致的错误： dispatch thunk of Ala [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>一个因为swift name mangled符号不一致导致的错误：</p>
<p>dispatch thunk of Alamofire.MultipartFormData.append(_: Foundation.Data, withName: Swift.String, fileName: Swift.String?, mimeType: Swift.String?) -&gt; ()&quot;, referenced from:</p>
<p>先说工程结构<br />
工程A有一个静态framework target a，通过cocoapods以源码方式集成了封装Alamofire，封装Alamofire的一些能力。</p>
<pre><code> workspace A
              |____ a (源码)
              |____Alamofire （源码）</code></pre>
<p>构建输出静态framework a。</p>
<p>工程B有一个App Target，通过cocoapods以源码方式集成封装Alamofire，以静态库方式集成了 a。</p>
<pre><code> workspace B
             ｜___App
                      |____ a (静态库)
                      |____ Alamofire （源码）
 ```

 在同一电脑，用同一个Xcode，设置了相同的swift version，结果App构建失败，找不到Alamofire里的符号。

经过一番观察，发现 &quot;dispatch thunk of Alamofire.MultipartFormData.append(...)&quot;是 Swift 编译器为带有默认参数、可变签名或需要方法桥接的函数生成的“thunk”符号。也就是说静态库a引用了这些由 Alamofire 生成的编译器私有符号，但最终链接器没有在任何被链接的库/框架中找到对应实现。

 检查工程配置，首先排除Alamofire 的实现没有被链接到最终可执行文件（常见：静态库a引用但 App 没把 Alamofire 链接上）。

那么，最有可能的情况就是：工程B的Alamofire 与 工程A  使用不同的 Swift 编译环境/选项，导致 thunk 的名称/生成方式不一致，最终没有可匹配的符号。虽然Alamofire代码一摸一样，但是编译后的符号修饰方式不一样。
</code></pre>
<p>示意例子，例如同样是方法 test，<br />
工程A中被修饰为 _$s12Alamofire4test<em>tKF<br />
工程B中被修饰为 </em>$s12Alamofire4test_tKj</p>
<pre><code>

有了排查方向，经过对比工程A和工程B的配置，最终发现cocoapods自动生成target Alamofire的配置有些许不一致 

Build Libraries for Distribution 这个配置不一样，一个是YES，一个是NO。
又经实验，发现如果依赖Alamofire的target的 Build Libraries for Distribution 配置为YES，那么cocoapods自动生成的Alamofire对应的配置也是YES。

最后，只要将Alamofire对应Build Libraries for Distribution设置为NO（保持一致）就解决了Undefined symbols问题。</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2026/01/23/undefined-symbols-dispatch-thunk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>using bridging headers with module interfaces is unsupported</title>
		<link>https://blog.z6z8.cn/2025/09/26/using-bridging-headers-with-module-interfaces-is-unsupported/</link>
					<comments>https://blog.z6z8.cn/2025/09/26/using-bridging-headers-with-module-interfaces-is-unsupported/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Fri, 26 Sep 2025 01:28:16 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1499</guid>

					<description><![CDATA[Xcode创建framework，选择语言Swift。在使用Swift语言编写framework时，如果要引入 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Xcode创建framework，选择语言Swift。在使用Swift语言编写framework时，如果要引入Objective-C的代码或者其他Objective-C的库，可能会报错“using bridging headers with module interfaces is unsupported”。这通常是因为在模块接口中使用了桥接头文件(bridging-header)，而这是不被支持的，</p>
<p>一般有两种解决办法：</p>
<p>一、如果这个framework不需要对外发布，那么将Build Setting里的Build Library For Distrubution 设置为NO，则可以继续使用桥接头文件(bridging-header)。</p>
<p>二、使用module map文件替换桥接头文件(bridging-header)，具体操作如下：</p>
<p>1、在framework工程里创建一个头文件，如<code>Test.h</code><br />
在Build Setting里设置User Header Search Paths，如<code>$(SRCROOT)/$(PRODUCT_NAME)</code>。设置的路径需要能找到<code>Test.h</code>文件</p>
<p>2、在<code>Test.h</code>文件里引入需要引用的Objective-C头文件</p>
<pre><code>#import &lt;MyLib/MyLib.h&gt;</code></pre>
<p>3、创建一个module map文件,<code>module.modulemap</code>，内容如下</p>
<pre><code>module  TestModule (名字自定义)  {
    header &quot;Test.h&quot;
    export *
}</code></pre>
<p>4、在Swift文件里，使用import指令，然后就可以调用Objective-C的方法了</p>
<pre><code>import  TestModule</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2025/09/26/using-bridging-headers-with-module-interfaces-is-unsupported/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>创建Objective-C可使用的Swift Framework</title>
		<link>https://blog.z6z8.cn/2025/09/24/%e5%88%9b%e5%bb%baobjective-c%e5%8f%af%e4%bd%bf%e7%94%a8%e7%9a%84swift-framework/</link>
					<comments>https://blog.z6z8.cn/2025/09/24/%e5%88%9b%e5%bb%baobjective-c%e5%8f%af%e4%bd%bf%e7%94%a8%e7%9a%84swift-framework/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Wed, 24 Sep 2025 06:53:58 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1497</guid>

					<description><![CDATA[默认创建的使用Swift语言编写的framework是没有头文件的，如果另一个使用Objective-C语言编 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>默认创建的使用Swift语言编写的framework是没有头文件的，如果另一个使用Objective-C语言编写的target想用引入swift framework，则需要在swift framework的工程上打开一些配置</p>
<h1>同时使用public 和 @objc标记</h1>
<p>要给Objective-C暴露swift编写的api，则需要使用public 和 @objc标记</p>
<pre><code class="language-swift">@objc public class MySwiftClass: NSObject {
    @objc public func doSomething() {
        print(&quot;Doing something in Swift&quot;)
    }
}</code></pre>
<h1>生成 Objective-C 兼容头文件</h1>
<p>Swift Framework 的 Build Settings 中：</p>
<ul>
<li>Defines Module 设置为 YES。</li>
<li>Install Generated Header 设置为 YES。<br />
这会生成一个 FrameworkName-Swift.h 头文件，包含 Swift 代码的 Objective-C 接口。</li>
</ul>
<h1>在 Objective-C 项目中导入导入 Swift Framework 的头文件</h1>
<pre><code class="language-objc">#import &lt;FrameworkName/FrameworkName-Swift.h&gt;

MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[swiftObject doSomething];</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2025/09/24/%e5%88%9b%e5%bb%baobjective-c%e5%8f%af%e4%bd%bf%e7%94%a8%e7%9a%84swift-framework/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>解析mach-o文件的依赖库列表，修改加载顺序</title>
		<link>https://blog.z6z8.cn/2024/10/29/%e8%a7%a3%e6%9e%90mach-o%e6%96%87%e4%bb%b6%e7%9a%84%e4%be%9d%e8%b5%96%e5%ba%93%e5%88%97%e8%a1%a8%ef%bc%8c%e4%bf%ae%e6%94%b9%e5%8a%a0%e8%bd%bd%e9%a1%ba%e5%ba%8f/</link>
					<comments>https://blog.z6z8.cn/2024/10/29/%e8%a7%a3%e6%9e%90mach-o%e6%96%87%e4%bb%b6%e7%9a%84%e4%be%9d%e8%b5%96%e5%ba%93%e5%88%97%e8%a1%a8%ef%bc%8c%e4%bf%ae%e6%94%b9%e5%8a%a0%e8%bd%bd%e9%a1%ba%e5%ba%8f/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 29 Oct 2024 06:45:17 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1475</guid>

					<description><![CDATA[两个命令可以解决，otool和install_name_tool otool和install_name_too [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>两个命令可以解决，otool和install_name_tool</p>
<h1>otool和install_name_tool</h1>
<pre><code># 显示依赖库列表
otool -L  &lt;mach-o文件路径&gt;</code></pre>
<pre><code># 添加新的依赖库路径
install_name_tool  -add_rpath  &lt;rpath&gt;   &lt;mach-o文件路径&gt;

# 删除依赖库路径
install_name_tool -delete_rpath  &lt;rpath&gt;  &lt;mach-o文件路径&gt;

# 替换依赖库路径
install_name_tool -change  &lt;old_rpath&gt;  &lt;new_rpath&gt;   &lt;mach-o文件路径&gt;</code></pre>
<h1>yololib 和ios App</h1>
<p>对于iOS App，install_name_tool的-add_rpath、  -delete_rpath总是执行失败，需要借助yololib工具添加依赖</p>
<pre><code># 删除iOS App 的依赖
install_name_tool -change 需要删除的依赖   替换的空依赖 #变相实现删除

# 排序iOS App 的依赖
# 不断执行 install_name_tool -change  ，实现排序</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2024/10/29/%e8%a7%a3%e6%9e%90mach-o%e6%96%87%e4%bb%b6%e7%9a%84%e4%be%9d%e8%b5%96%e5%ba%93%e5%88%97%e8%a1%a8%ef%bc%8c%e4%bf%ae%e6%94%b9%e5%8a%a0%e8%bd%bd%e9%a1%ba%e5%ba%8f/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【转】xcode: iOS 17.x not installed</title>
		<link>https://blog.z6z8.cn/2024/09/10/%e3%80%90%e8%bd%ac%e3%80%91xcode-ios-17-x-not-installed/</link>
					<comments>https://blog.z6z8.cn/2024/09/10/%e3%80%90%e8%bd%ac%e3%80%91xcode-ios-17-x-not-installed/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 10 Sep 2024 10:20:36 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1472</guid>

					<description><![CDATA[运行命令，sudo killall -9 com.apple.CoreSimulator.CoreSimula [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>运行命令，sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService<br />
然后重启Xcode</p>
<p><a href="https://forums.developer.apple.com/forums/thread/751049">https://forums.developer.apple.com/forums/thread/751049</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2024/09/10/%e3%80%90%e8%bd%ac%e3%80%91xcode-ios-17-x-not-installed/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>为iOS构建libarchive</title>
		<link>https://blog.z6z8.cn/2024/08/05/%e4%b8%baios%e6%9e%84%e5%bb%balibarchive/</link>
					<comments>https://blog.z6z8.cn/2024/08/05/%e4%b8%baios%e6%9e%84%e5%bb%balibarchive/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Mon, 05 Aug 2024 02:13:18 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1467</guid>

					<description><![CDATA[引用 libarchive源码 https://github.com/libarchive/libarchiv [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>引用</h1>
<p>libarchive源码  <a href="https://github.com/libarchive/libarchive/tree/v3.7.4">https://github.com/libarchive/libarchive/tree/v3.7.4</a></p>
<p>cmake工具手册<br />
<a href="https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos">https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos</a></p>
<h1>基本操作</h1>
<p>需要安装cmake（brew install cmake）</p>
<p>然后使用cmake为libarchive配置xcode工程</p>
<pre><code>cd 源码目录
cmake -S. -B_builds -GXcode -DCMAKE_SYSTEM_NAME=iOS #结果输出到_builds文件夹</code></pre>
<p>一般会遇到以下错误</p>
<pre><code>CMake Error at cat/CMakeLists.txt:33 (INSTALL):
  INSTALL TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE executable
  target &quot;bsdcat&quot;.

CMake Error at tar/CMakeLists.txt:46 (INSTALL):
  INSTALL TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE executable
  target &quot;bsdtar&quot;.

CMake Error at cpio/CMakeLists.txt:42 (INSTALL):
  INSTALL TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE executable
  target &quot;bsdcpio&quot;.

CMake Error at unzip/CMakeLists.txt:37 (INSTALL):
  INSTALL TARGETS given no BUNDLE DESTINATION for MACOSX_BUNDLE executable
  target &quot;bsdunzip&quot;.</code></pre>
<p>以上错误的原因是iOS App并不支持MACOSX_BUNDLE，在CMakeLists.txt中注释对应的INSTALL动作就可以了</p>
<pre><code>  例如对于bsdtar ,打开tar/CMakeLists.txt ，搜索以下两行，加上 # 注释
 # INSTALL(TARGETS bsdtar RUNTIME DESTINATION bin)
 # INSTALL_MAN(${bsdtar_MANS})</code></pre>
<p>最后，删除输出文件夹（_builds文件夹），重新执行cmake命令</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2024/08/05/%e4%b8%baios%e6%9e%84%e5%bb%balibarchive/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>iOS13 同一App实现多窗口（iPad和Vision平台）</title>
		<link>https://blog.z6z8.cn/2024/02/26/ios13-%e5%90%8c%e4%b8%80app%e5%ae%9e%e7%8e%b0%e5%a4%9a%e7%aa%97%e5%8f%a3%ef%bc%88ipad%e5%92%8cvision%e5%b9%b3%e5%8f%b0%ef%bc%89/</link>
					<comments>https://blog.z6z8.cn/2024/02/26/ios13-%e5%90%8c%e4%b8%80app%e5%ae%9e%e7%8e%b0%e5%a4%9a%e7%aa%97%e5%8f%a3%ef%bc%88ipad%e5%92%8cvision%e5%b9%b3%e5%8f%b0%ef%bc%89/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Mon, 26 Feb 2024 09:54:22 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[代码片段]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1448</guid>

					<description><![CDATA[在Info.plist中配置多窗口支持 Enable Multiple Windows 置为 YES 新建一个 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>在Info.plist中配置多窗口支持</h1>
<ul>
<li>Enable Multiple Windows 置为 YES</li>
<li>新建一个Scene配置（如果只有一个窗口，则不需要此操作）</li>
</ul>
<p><img decoding="async" src="/wp-content/uploads/2024/02/1-300x94.png" alt="" /></p>
<h1>判断当前环境是否支持多窗口</h1>
<p>iOS13及以上支持多窗口；iPad设备和Vision设备支持，但iPhone不支持。</p>
<pre><code class="language-objc"> if (@available(iOS 13.0, *))
{
    if (UIApplication.sharedApplication.supportsMultipleScenes)
    {// Info.plist也配置了多窗口开关

        if  (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad
            || UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomVision)
        {
            //支持多窗口
        }
    }
}</code></pre>
<h1>使用API创建新窗口</h1>
<h2>创建新的SceneDelegate</h2>
<p>当App启用Scene后，需要使用Scene管理Window。为了管理新窗口，我们新建一个SceneDelegate</p>
<pre><code class="language-objc">
@interface SecondSceneDelegate : UIResponder &lt; UIWindowSceneDelegate ,NSUserActivityDelegate&gt;

@property (nonatomic,strong) UIWindow * window;

@end

@implementation SecondSceneDelegate
// 将要连接到某个场景（Window需要依附在具体场景）
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
{
    if (self.window == nil)
    {
        SecondSceneViewController *vc = [[SecondSceneViewController alloc] init]; // 自己定义的页面
        UINavigationController *naviVc = [[UINavigationController alloc] initWithRootViewController:vc];//页面导航
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.windowScene = (UIWindowScene *)scene;
        self.window.rootViewController = naviVc;
        [self.window makeKeyAndVisible];
    }
}
@end
</code></pre>
<h2>创建新窗口</h2>
<p>使用<code>requestSceneSessionActivation</code></p>
<pre><code class="language-objc">NSUserActivity * activity = [[NSUserActivity alloc] initWithActivityType:@&quot;open_by_first&quot;];
[UIApplication.sharedApplication requestSceneSessionActivation:nil  //此参数为nil时，表示要求系统创建一个SceneSession
                                                  userActivity:activity
                                                       options:optios
                                                  errorHandler:^(NSError * _Nonnull error) {
    NSLog(@&quot;%@&quot;,error);
}];
</code></pre>
<h1>同时兼容iOS13及以上和iOS12及以下</h1>
<p>请先去除工程中的StoryBoard的相关配置（否则，以下代码可能不会完全生效）。</p>
<h2>在Info.plist中配置多窗口支持（参考上文）</h2>
<p>略</p>
<h2>修改AppDelegate</h2>
<pre><code class="language-objc">
@interface AppDelegate : UIResponder &lt;UIApplicationDelegate&gt;

@property (nullable, nonatomic, strong) UIWindow *window; // 添加属性，注意这是UIApplicationDelegate的协议实现

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (@available(iOS 13.0, *))
    { //iOS 13，启用Scene后，窗口在Scene的实现里创建
        return YES;
    }
    else
    {
        FirstSceneViewController *vc = [[FirstSceneViewController alloc] init]; // 自己定义的页面
        UINavigationController *naviVc = [[UINavigationController alloc] initWithRootViewController:vc];//页面导航
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.rootViewController = naviVc;
        [self.window makeKeyAndVisible];
        return YES;
    }
}

- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options 
{
    NSString *cfgName = @&quot;FirstScene&quot;; //场景名字
    if ([options.userActivities.objectEnumerator.nextObject.activityType isEqualToString:@&quot;open_by_first&quot;]) //使用哪个场景
    {
        cfgName = @&quot;SecondScene&quot;;
    }
    return [[UISceneConfiguration alloc] initWithName:cfgName sessionRole:connectingSceneSession.role];
}
@end
</code></pre>
<h2>创建（修改）SceneDelegate</h2>
<p>为求简单，本文采用多组<code>Window+SceneDelegate</code>来管理多个窗口，即每个Window都有自己的SceneDelegate。本文实现了两个窗口的情形。</p>
<p>第一个SceneDelegate代码如下</p>
<pre><code class="language-objc">
@interface FirstSceneDelegate : UIResponder &lt;UIWindowSceneDelegate&gt;

@property (strong, nonatomic) UIWindow * window;

@end

@implementation FirstSceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions 
{
    session.userInfo = @{@&quot;userData&quot;:@&quot;first_session&quot;};
    if (self.window == nil)
    {
        FirstSceneViewController *vc = [[FirstSceneViewController alloc] init]; // 自己定义的页面
        UINavigationController *naviVc = [[UINavigationController alloc] initWithRootViewController:vc];//页面导航
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.windowScene = (UIWindowScene *)scene;
        self.window.rootViewController = naviVc;
        [self.window makeKeyAndVisible];
    }
}
@end
</code></pre>
<p>第二个SceneDelegate代码如下</p>
<pre><code class="language-objc">
@interface SecondSceneDelegate : UIResponder &lt; UIWindowSceneDelegate ,NSUserActivityDelegate&gt;

@property (nonatomic,strong) UIWindow * window;

@end

@implementation SecondSceneDelegate

// 将要连接到某个场景（Window需要依附在具体场景）
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
{
    session.userInfo = @{@&quot;userData&quot;:@&quot;second_session&quot;};
    if (self.window == nil)
    {
        SecondSceneViewController *vc = [[SecondSceneViewController alloc] init]; // 自己定义的页面
        UINavigationController *naviVc = [[UINavigationController alloc] initWithRootViewController:vc];//页面导航
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.windowScene = (UIWindowScene *)scene;
        self.window.rootViewController = naviVc;
        [self.window makeKeyAndVisible];
    }

}

@end
</code></pre>
<h2>在第一个窗口的页面下，使用按钮打开第二个窗口</h2>
<p>按钮事件响应</p>
<pre><code class="language-objc">- (void)onClickButton:(id)sender
{
    if (@available(iOS 13.0, *))
    {
        if (UIApplication.sharedApplication.supportsMultipleScenes)
        {
            if  (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad
                 || UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomVision)
            {

                // 查找，确定是否已经打开过
                UISceneSession *foundSession = nil;
                NSString * foundStr = @&quot;second_session&quot;;
                for (UISceneSession * session in UIApplication.sharedApplication.openSessions)
                {
                    if (session.userInfo &amp;&amp; [foundStr isEqualToString:session.userInfo[@&quot;userData&quot;]])
                    {
                        foundSession = session;
                        break;
                    }
                }

                UISceneActivationRequestOptions *optios = nil;
                if (foundSession) // 已存在，激活即可
                {
                    [UIApplication.sharedApplication requestSceneSessionActivation:foundSession
                                                                      userActivity:nil
                                                                           options:optios
                                                                      errorHandler:^(NSError * _Nonnull error) {
                        NSLog(@&quot;%@&quot;,error);
                    }];
                }
                else // 新建场景
                {
                    NSUserActivity * activity = [[NSUserActivity alloc] initWithActivityType:@&quot;open_by_first&quot;];
                    [UIApplication.sharedApplication requestSceneSessionActivation:nil 
                                                                      userActivity:activity
                                                                           options:optios
                                                                      errorHandler:^(NSError * _Nonnull error) {
                        NSLog(@&quot;%@&quot;,error);
                    }];
                }
            }
        }
    }
}
</code></pre>
<h1>其他注意事项</h1>
<ul>
<li>启用Scene后，UIAlertView将无法使用（运行时崩溃），需要用UIAlertController进行替换</li>
<li>在iPad端，实现多窗口时，需要将Info.list里的<code>Requires full screen</code>置为false，同时要设置为支持所有屏幕方向。否则可能会收到类似错误“the delegate of workspace fbscenemanger declined to create scene”<br />
<img decoding="async" src="/wp-content/uploads/2024/02/截屏2024-03-01-16.29.54-300x99.png" alt="" /></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2024/02/26/ios13-%e5%90%8c%e4%b8%80app%e5%ae%9e%e7%8e%b0%e5%a4%9a%e7%aa%97%e5%8f%a3%ef%bc%88ipad%e5%92%8cvision%e5%b9%b3%e5%8f%b0%ef%bc%89/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Swift 语言编写静态Framework，引用Objective-C文件</title>
		<link>https://blog.z6z8.cn/2023/08/14/swift-%e8%af%ad%e8%a8%80%e7%bc%96%e5%86%99%e9%9d%99%e6%80%81framework%ef%bc%8c%e5%bc%95%e7%94%a8objective-c%e6%96%87%e4%bb%b6/</link>
					<comments>https://blog.z6z8.cn/2023/08/14/swift-%e8%af%ad%e8%a8%80%e7%bc%96%e5%86%99%e9%9d%99%e6%80%81framework%ef%bc%8c%e5%bc%95%e7%94%a8objective-c%e6%96%87%e4%bb%b6/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Mon, 14 Aug 2023 09:00:53 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1445</guid>

					<description><![CDATA[1、将Objective-C头文件拖入framework工程引用，应可在以下路径看到头文件 Build Pha [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>1、将Objective-C头文件拖入framework工程引用，应可在以下路径看到头文件</p>
<pre><code>Build Phases -&gt; Headers -&gt; Project </code></pre>
<p>2、创建Bridge头文件，如 “TestBridging.h”，并填入头文件的相对路径</p>
<pre><code>Build Settings -&gt; Swift Compiler General -&gt; Objective-C Bridging Header -&gt; xxxx/TestBridging.h</code></pre>
<p>3、在Bridge头文件中引用Objective-C头文件 （不用使用&lt;&gt;形式引用）</p>
<pre><code>// TestBridging.h

#import &quot;A.h&quot;
#import &quot;B.h&quot;
#import &quot;C.h&quot;
</code></pre>
<p>4、关闭 defines Module</p>
<pre><code>Build Settings -&gt; Packaging -&gt; Defines Module -&gt; No</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2023/08/14/swift-%e8%af%ad%e8%a8%80%e7%bc%96%e5%86%99%e9%9d%99%e6%80%81framework%ef%bc%8c%e5%bc%95%e7%94%a8objective-c%e6%96%87%e4%bb%b6/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Swift 注解 @resultBuilder</title>
		<link>https://blog.z6z8.cn/2023/06/28/swift-%e6%b3%a8%e8%a7%a3-resultbuilder/</link>
					<comments>https://blog.z6z8.cn/2023/06/28/swift-%e6%b3%a8%e8%a7%a3-resultbuilder/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Wed, 28 Jun 2023 10:27:21 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1438</guid>

					<description><![CDATA[使用SwiftUI时，经常会遇到@ViewBuilder，代码看起来很简洁，背后确实复杂的语法规则。 本文涉及 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>使用SwiftUI时，经常会遇到@ViewBuilder，代码看起来很简洁，背后确实复杂的语法规则。</p>
<p>本文涉及三点：</p>
<ul>
<li>@resultBuilder</li>
<li>可变参数</li>
<li>闭包以及尾随闭包</li>
</ul>
<p>我们可以自己定义一个类似@ViewBuilder的注解，本文将实现一个自定义的字符串拼接的注解。</p>
<p>首先 用 <code>@resultBuilder</code>修饰的 struct符号需要实现静态<code>buildBlock</code>方法</p>
<pre><code class="language-swift">@resultBuilder public struct TestStringBuilder {
    public static func buildBlock( s1 : String ,s2 : String) -&gt; String {
        return s1 + s2
    }
}</code></pre>
<p>然后定义一个函数，只有一个闭包参数，参数使用<code>@TestStringBuilder</code>修饰</p>
<pre><code class="language-swift">func  test_string_builder(@TestStringBuilder strs_join: () -&gt; String ) {
    print(strs_join())
}</code></pre>
<p>现在可以给<code>test_string_builder</code>传入闭包参数了</p>
<pre><code class="language-swift">test_string_builder( strs_join :{
    &quot;a&quot;
    &quot;b&quot;
})

//将打印字符串 “ab”</code></pre>
<p>该尾随闭包出场了，它是一个书写在函数括号之后的闭包表达式，函数支持将其作为最后一个参数调用</p>
<pre><code class="language-swift">test_string_builder(){
    &quot;a&quot;
    &quot;b&quot;
}

//将打印字符串 “ab”</code></pre>
<p>如果函数只需要闭包表达式一个参数，当您使用尾随闭包时，可以把()省略掉</p>
<pre><code class="language-swift">test_string_builder{
    &quot;a&quot;
    &quot;b&quot;
}

//将打印字符串 “ab”</code></pre>
<p>现在是不是有点像@ViewBuilder的用法了？最后是可变参数，修改下<code>buildBlock</code>定义，以支持可变参数</p>
<pre><code class="language-swift">@resultBuilder public struct TestStringBuilder {
    public static func buildBlock(_ strs: String...) -&gt; String {
        var ret = &quot;&quot;
        for s in strs {
            ret = ret + s
        }
        return ret
    }
}</code></pre>
<p>最终<code>test_string_builder</code>的用法</p>
<pre><code class="language-swift">test_string_builder {
    &quot;a&quot;
    &quot;b&quot;
    &quot;c&quot;
    &quot;d&quot;
}

//将打印字符串 “abcd”</code></pre>
<p>@ViewBuilder的原理和上面类似。</p>
<p>吐槽下，编译器做了很多事，以至于让人习惯语法糖后忘记了该有的本来面目。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2023/06/28/swift-%e6%b3%a8%e8%a7%a3-resultbuilder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>file system sandbox blocked mmap()</title>
		<link>https://blog.z6z8.cn/2023/05/04/file-system-sandbox-blocked-mmap/</link>
					<comments>https://blog.z6z8.cn/2023/05/04/file-system-sandbox-blocked-mmap/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Thu, 04 May 2023 01:46:17 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<guid isPermaLink="false">https://blog.z6z8.cn/?p=1427</guid>

					<description><![CDATA[不允许从沙盒目录加载动态库（代码），尤其是在生产环境上。 在iOS9中，还没有这么严格的管控要求，在iOS10 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>不允许从沙盒目录加载动态库（代码），尤其是在生产环境上。<br />
在iOS9中，还没有这么严格的管控要求，在iOS10+后要求更加严格了。</p>
<p><a href="https://developer.apple.com/forums/thread/711730">https://developer.apple.com/forums/thread/711730</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2023/05/04/file-system-sandbox-blocked-mmap/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
