<?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/"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>swift 归档 - Tinyfool的个人网站</title>
	<atom:link href="https://codechina.org/tag/swift/feed/" rel="self" type="application/rss+xml" />
	<link>https://codechina.org/tag/swift/</link>
	<description></description>
	<lastBuildDate>Sun, 19 May 2024 06:17:29 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Swift编程中应用@available和deprecated在自己的编程中提供便利</title>
		<link>https://codechina.org/2024/04/30772/</link>
					<comments>https://codechina.org/2024/04/30772/#comments</comments>
		
		<dc:creator><![CDATA[tinyfool]]></dc:creator>
		<pubDate>Thu, 25 Apr 2024 02:52:49 +0000</pubDate>
				<category><![CDATA[iOS开发]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[swift]]></category>
		<category><![CDATA[swiftui]]></category>
		<guid isPermaLink="false">https://codechina.org/?p=30772</guid>

					<description><![CDATA[<p>在 Swift 中，@available 是一个属性标注（Attribute），它用来表示一个类、结构体、枚举 [&#8230;]</p>
<p><a href="https://codechina.org/2024/04/30772/">Swift编程中应用@available和deprecated在自己的编程中提供便利</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p>在 Swift 中，@available 是一个属性标注（Attribute），它用来表示一个类、结构体、枚举、函数或者方法等的可用性信息，指示特定的平台和版本。通过这个属性标注，开发者可以对代码中的各个部分设定适用的操作系统平台及最低支持的版本，也可以指定在某个版本中它们已经过期或不推荐使用，甚至是未来某个版本中会被添加的特性。</p>



<p>我们使用苹果的标准 Swift 库的时候，经常遇到 @available ，一个老代码的某个函数调用，系统升级后，可能会发现一个警告，</p>



<pre class="wp-block-code"><code class="">'oldMethod(text:messages:key:)' is deprecated: Use newMethod() instead</code></pre>



<p>意思就是这个方法或者函数，现在已经被废弃了，最好不要再使用。在这个情况下，往往你其实还可以编译还可以执行。但是这些被废弃的老方法，要么也许有 bug ，或者系统的代码风格，习惯变了，已经被推荐使用了。有的人觉的既然可以编译和执行，何必理会呢？其实不然，有些方法会在某一个操作系统版本废弃，然后在后续的某个大操作系统版本就彻底消失，无法编译和运行。也就是说，废弃声明就是提醒你可以修改代码了，未来这个方法或者类有可能完全不能用了。最好尊重这些声明来写代码。</p>



<p>我们去看系统代码和头文件的时候，会看到很多类似的例子：</p>



<pre class="wp-block-code"><code class="">1. 指定功能在平台上的最小可用版本：<br>@available(iOS 10, *)<br>func newiOS10Method() {<br>    // 这个方法只会在 iOS 10 及以上版本可用<br>}<br><br>2. 标示一个功能在新版本中被弃用：<br>@available(iOS, deprecated: 11.0, message: "Use newMethod instead")<br>func oldMethod() {<br>    // 这个方法在 iOS 11 中被标记为弃用<br>}<br><br>3. 标示一个功能在新版本中被废弃或移除：<br>@available(iOS, obsoleted: 11.0, message: "Use anotherMethod instead")<br>func obsoleteMethod() {<br>    // 这个方法从 iOS 11 开始就废弃了，调用它会出错<br>}<br><br>4. 标示功能未来新增：<br>@available(iOS 15, *)<br>func futureMethod() {<br>    // 这个方法在未来的 iOS 15 版本中会被添加<br>}<br><br>5. 跨多平台设置可用性：<br>@available(iOS 10, macOS 10.12, *)<br>func crossPlatformMethod() {<br>    // 这个方法在 iOS 10 和 macOS 10.12 及以上版本都可用<br>}<br><br>6. 为不同的平台指定不同的最小版本：<br>@available(iOS 14, watchOS 7, *)<br>func multiPlatformMethod() {<br>    // 对于 iOS 平台，这个方法要求版本 14.0 及以上<br>    // 对于 watchOS 平台，这个方法要求版本 7.0 及以上<br>}</code></pre>



<p>但是，这是一般情况下我们接触的 @available 和 deprecated。其实我们自己的代码里面也可以用这些用法。比如我最近在给 <a href="https://tinystudio.ai/">TinyStudio（最好的Mac字幕软件之一）</a>增加新的功能，代码里面涉及到如何调用 ChatGPT，以及用 ChatGPT 来进行一些复杂的字幕后续处理操作。</p>



<p>在此之前我不知道 Swift 的 await 和 actor 语法，所以涉及到 ChatGPT 的代码非常复杂，比如一个巨长的文本发给 ChatGPT 需要实现分段，然后一段一段的去调用 ChatGPT 来进行处理。代码就非常复杂，我用递归调用和回调函数的方法来做，非常麻烦。虽然我可以轻松的写出这样的代码，但是这样的代码在调试、调优和异常处理方面简直是噩梦。</p>



<p>我知道了 Swift 的 await 和 actor 语法后，发现这个场景用这些并发语法来写，代码可以变得非常简洁，而且在调试、调优和异常处理方面非常方便。于是我就着手写 ChatGPT 和文本处理库的异步版本（await/actor）。写的时候，原有的函数叫 send ，新版本就叫做 asyncSend，原有的函数叫 format，新的就叫做 asyncFormat。</p>



<p>初步实现以后，我发现原有的 send 和 format 在很多地方都有调用，直接用文字搜索也会遇到一些类似的函数名。于是我就想起了 @available 和 deprecated 语法。</p>



<p>首先，我先把 ChatGPTKit 类和 TextKit 类的新老版本函数，放在不同的 extension 里（不影响执行，但是从代码来看，就可以把不同类型的方法条理清晰的分明白了）：</p>



<pre class="wp-block-code"><code class="">// 遗留版本函数<br>extension TextKit {<br><br>    func format(textString)  {<br>...<br><br>// 遗留版本函数<br>extension TextKit {<br><br>    func asyncFormat(textString)  {<br>...</code></pre>



<p>然后，在遗留版本函数的 extension 声明前，标注 @available 即可：</p>



<pre class="wp-block-code"><code class="">// 遗留版本函数<br><strong>@available</strong>(*, deprecated, message: "老版本已废弃，请使用异步版本")<br>extension TextKit {<br><br>    func format(textString)  {<br>...<br></code></pre>



<p>这时候编译程序，就会发现还在用老版本函数的代码就会被编译器发出警告，然后我们根据警告信息，一一替换为新版本就好了。如下：</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="682" height="122" src="https://codechina.org/wp-content/uploads/2024/04/截屏2024-04-25-10.41.43-1.png" alt="" class="wp-image-30781" srcset="https://codechina.org/wp-content/uploads/2024/04/截屏2024-04-25-10.41.43-1.png 682w, https://codechina.org/wp-content/uploads/2024/04/截屏2024-04-25-10.41.43-1-300x54.png 300w" sizes="(max-width: 682px) 100vw, 682px" /></figure>
<p><a href="https://codechina.org/2024/04/30772/">Swift编程中应用@available和deprecated在自己的编程中提供便利</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codechina.org/2024/04/30772/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			<media:content url="https://codechina.org/wp-content/uploads/2024/04/截屏2024-04-25-10.51.11-1.png" medium="image" />
	</item>
		<item>
		<title>从零开始，使用SwiftUI和PDFKit快速构建完全可定制的PDF阅读器</title>
		<link>https://codechina.org/2023/01/26809/</link>
					<comments>https://codechina.org/2023/01/26809/#respond</comments>
		
		<dc:creator><![CDATA[tinyfool]]></dc:creator>
		<pubDate>Tue, 03 Jan 2023 13:39:05 +0000</pubDate>
				<category><![CDATA[iOS开发]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[pdfkit]]></category>
		<category><![CDATA[swift]]></category>
		<category><![CDATA[swiftui]]></category>
		<guid isPermaLink="false">https://codechina.org/?p=26809</guid>

					<description><![CDATA[<p>SwiftUI快速创建UI的能力非常强大，苹果还提供了PDFKit框架，所以，用SwiftUI和PDFKit可 [&#8230;]</p>
<p><a href="https://codechina.org/2023/01/26809/">从零开始，使用SwiftUI和PDFKit快速构建完全可定制的PDF阅读器</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p>SwiftUI快速创建UI的能力非常强大，苹果还提供了PDFKit框架，所以，用SwiftUI和PDFKit可以用非常少的代码，非常快速的创建一个完全可定制的PDF阅读器。</p>



<p>我们来从零开始，做一个PDF阅读器。</p>



<span id="more-26809"></span>



<h2 class="wp-block-heading">创建项目</h2>



<p>首先，打开Xcode，创建一个新的iOS App。项目名字可以就叫做PdfReader。Interface选择Swift UI，language选择Swift。</p>



<p>因为PDFKit是一个UIKit库，不是原生的SwiftUI对象，所以，我们先需要做一个UIViewRepresentable类，来作为两者之间的桥梁。我已经帮你准备好了一个。你只需要创建一个SwiftPDFView.swift，把如下代码复制进去即可。</p>



<pre class="wp-block-code"><code lang="swift" class="language-swift">//
//  SwiftPDFView.swift
//  PdfReader
//
//  Created by HaoPeiqiang on 2023/1/3.
//

import SwiftUI
import PDFKit

struct SwiftPDFView: UIViewRepresentable {

    
    let url:URL

    func makeUIView(context: Context) -&gt; PDFView {
        
        let pdfView = PDFView()
        pdfView.document = PDFDocument(url: url)
        pdfView.displayMode = .singlePage
        pdfView.autoScales = true
        pdfView.usePageViewController(true, withViewOptions: nil)
        return pdfView
    }
    
    
    func updateUIView(_ pdfView: PDFView, context: Context) {
        
    }

}

struct SwiftPDFView_Previews: PreviewProvider {
    static var previews: some View {
        
        SwiftPDFView(url:Bundle.main.url(forResource: "sample_pdf", withExtension: "pdf")!)
    }
}
</code></pre>



<p>然后，你可以找到自动生成的ContentView.swift文件，把在body内部自动生成的代码删除，加上<code>SwiftPDFView(url: Bundle.main.url(forResource: "sample_pdf", withExtension: "pdf")!)</code>。好，三分钟不到，你已经成功创建了一个PDF阅读器了。</p>



<p>如果你打开了Xcode代码区域右侧的预览区域，都不用执行App，你已经可以看到你的PDF浏览器已经可以工作了，也可以在PDF页面之间翻页。</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="662" src="https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1024x662.png" alt="" class="wp-image-26819" srcset="https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1024x662.png 1024w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-300x194.png 300w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-768x496.png 768w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1536x993.png 1536w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-2048x1324.png 2048w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1200x776.png 1200w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1980x1280.png 1980w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">加入缩略图导航栏</h2>



<p>你可能见过有的PDF App，在PDF页面下方有一排缩略图，可以导航也可以预览PDF的文件内容，这个叫做<code>PDFThumbnailView</code>。加入<code>PDFThumbnailView</code>可以让我们的PDF阅读器，看起来更专业。</p>



<p>我们可以回到<code>SwiftPDFView.swift</code>文件，在SwiftPDFView类的代码里面加入如下代码：</p>



<pre class="wp-block-code"><code lang="swift" class="language-swift">    func setThumbnailView(_ pdfView:PDFView) {
        let thumbnailView = PDFThumbnailView()
        thumbnailView.translatesAutoresizingMaskIntoConstraints = false
        pdfView.addSubview(thumbnailView)
        
        thumbnailView.leadingAnchor.constraint(equalTo: pdfView.safeAreaLayoutGuide.leadingAnchor).isActive = true
        thumbnailView.trailingAnchor.constraint(equalTo: pdfView.safeAreaLayoutGuide.trailingAnchor).isActive = true
        thumbnailView.bottomAnchor.constraint(equalTo: pdfView.safeAreaLayoutGuide.bottomAnchor).isActive = true
        thumbnailView.bottomAnchor.constraint(equalTo: pdfView.safeAreaLayoutGuide.bottomAnchor).isActive = true
        
        thumbnailView.heightAnchor.constraint(equalToConstant: 40).isActive = true

        thumbnailView.thumbnailSize = CGSize(width: 20, height: 30)
        thumbnailView.layoutMode = .horizontal
        thumbnailView.pdfView = pdfView
    }
</code></pre>



<p>然后在刚才的<code>makeUIView</code>方法，<code>return pdfView</code>之前加入一句<code><strong>self</strong>.setThumbnailView(pdfView)</code>即可。</p>



<p>然后，查看预览区域，就会发现PDF显示区域下面出现了缩略图导航栏。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="964" height="610" src="https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-21.33.40.png" alt="" class="wp-image-26825" srcset="https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-21.33.40.png 964w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-21.33.40-300x190.png 300w, https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-21.33.40-768x486.png 768w" sizes="(max-width: 964px) 100vw, 964px" /></figure>



<p>项目代码可从Github下载 <a href="https://github.com/Swift-Cast/PdfReader">https://github.com/Swift-Cast/PdfReader</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><a href="https://iapp4me.com/pdf-extractor">PDF Extractor &#8211; Extract text/images from PDF</a></p>
<p><a href="https://codechina.org/2023/01/26809/">从零开始，使用SwiftUI和PDFKit快速构建完全可定制的PDF阅读器</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codechina.org/2023/01/26809/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://codechina.org/wp-content/uploads/2023/01/截屏2023-01-03-20.49.53-1024x662.png" medium="image" />
	</item>
		<item>
		<title>Xcode 12 比 Xcode 11 有很多改进， 我遇到的一个具体案例</title>
		<link>https://codechina.org/2020/07/1700/</link>
					<comments>https://codechina.org/2020/07/1700/#respond</comments>
		
		<dc:creator><![CDATA[tinyfool]]></dc:creator>
		<pubDate>Fri, 17 Jul 2020 02:00:02 +0000</pubDate>
				<category><![CDATA[iOS开发]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[if]]></category>
		<category><![CDATA[swift]]></category>
		<category><![CDATA[swiftui]]></category>
		<category><![CDATA[xcode]]></category>
		<guid isPermaLink="false">https://codechina.org/?p=1700</guid>

					<description><![CDATA[<p>编译差异 最近同时使用 Xcode 11 和 Xcode beta (也就是12)，发现，后者性能提升超级明显 [&#8230;]</p>
<p><a href="https://codechina.org/2020/07/1700/">Xcode 12 比 Xcode 11 有很多改进， 我遇到的一个具体案例</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">编译差异</h2>



<p>最近同时使用 Xcode 11 和 Xcode beta (也就是12)，发现，后者性能提升超级明显，而编译器的理解能力也提升很多。</p>



<p>比如，我的一个SwiftUI代码里面，有一个稍微复杂一点的判断逻辑，有三个 if/else 分支，如下：</p>



<pre class="wp-block-code"><code lang="swift" class="language-swift line-numbers">Group {
    if(index>0 &amp;&amp; item.rating>4.0) {
        PoiLargeImageCell(item:item)
    }else if(index==0){
        InvisibleCell(largeHeadView:self.$largeHeadView)
        PoiCell(item: item)
    }else {
        PoiCell(item: item)
    }
}</code></pre>



<p>这个代码在 Xcode 12 可以正常编译，没有任何问题。但是，在 Xcode 11 下就会直接报错，而且是那种完全文不对题的错误信息。错误信息不是在 Swift 5 发布后有改善了么？但是在这个问题下仍旧文不对题，所以，我只能把这个稍微复杂一点的 if/else 语句改为两个 Group  嵌套的做法，如下，这样在 Xcode 11 就可以正常编译了。</p>



<pre class="wp-block-code"><code lang="swift" class="language-swift">Group {
    if(index==0){
        ZStack{
            InvisibleCell(largeHeadView:self.$largeHeadView)
            PoiCell(item: item)
        }
    }else {
        Group {
            if(index>0 &amp;&amp; item.rating>4.0){
                PoiLargeImageCell(item:item)
            }else {
                PoiCell(item: item)
            }
        }
    }
}</code></pre>



<p>为了迁就编译器，代码变啰嗦多了。不过暂时需要这么做，期待 Xcode 12 早日正式发布。这么多年以来，第一次感觉苹果的 Beta 版本这么靠谱，感觉苹果今年果然有点进步。</p>



<h2 class="wp-block-heading">提交上出现的错误信息</h2>



<p>今天我用 Xcode 11 提交一个 app ，遇到了一个以前没见过的错误信息，“Profile doesn&#8217;t include the com.apple.application-identifier entitlement.”。查了下，原来跟 MacOS Big Sur 有关系，跟 Xcode 11 和 Xcode 12 beta 也有关系。解决方法很搞笑，那就是用 Xcode 11来编译打包，用 Xcode 12 beta 来 upload app。详情可以参考<a href="https://developer.apple.com/forums/thread/650438">苹果开发者论坛的相关帖子</a>。</p>
<p><a href="https://codechina.org/2020/07/1700/">Xcode 12 比 Xcode 11 有很多改进， 我遇到的一个具体案例</a>最先出现在<a href="https://codechina.org">Tinyfool的个人网站</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codechina.org/2020/07/1700/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://codechina.org/wp-content/uploads/2020/07/screen-hero-large.jpg" medium="image" />
	</item>
	</channel>
</rss>
