<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>NonAtomicInk</title>
    <link>https://atomicink.github.io/</link>
    <description>Recent content on NonAtomicInk</description>
    <image>
      <title>NonAtomicInk</title>
      <url>https://atomicink.github.io/images/avatar.png</url>
      <link>https://atomicink.github.io/images/avatar.png</link>
    </image>
    <generator>Hugo -- 0.147.8</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 09 Jun 2025 11:24:40 +0800</lastBuildDate>
    <atom:link href="https://atomicink.github.io/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>关于 Block 与异步重试的设计模式</title>
      <link>https://atomicink.github.io/posts/guan-yu-block-yu-yi-bu-chong-shi-de-she-ji-mo-shi/</link>
      <pubDate>Mon, 09 Jun 2025 11:24:40 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/guan-yu-block-yu-yi-bu-chong-shi-de-she-ji-mo-shi/</guid>
      <description>&lt;h3 id=&#34;背景&#34;&gt;背景&lt;/h3&gt;
&lt;p&gt;在开发中，实现一个带重试机制的异步任务是一个常见需求。最近，我在实现一个启动页数据加载的功能时，对重试逻辑的实现方式进行了深入的思考和实践，并踩了一些典型的坑。本文旨在记录两种截然不同的实现思路，分析其优劣，并反思为什么开发者有时会选择一个更复杂甚至错误的方案。&lt;/p&gt;
&lt;h3 id=&#34;两种实现方案&#34;&gt;两种实现方案&lt;/h3&gt;
&lt;p&gt;我们以一个通用的重试辅助方法 &lt;code&gt;executeRetryableTask&lt;/code&gt; 为例，对比两种实现。&lt;/p&gt;
&lt;h4 id=&#34;方案一复杂的-block-自引用有缺陷&#34;&gt;方案一：复杂的 Block 自引用（有缺陷）&lt;/h4&gt;
&lt;p&gt;这种方案试图将重试逻辑封装在一个自包含的 Block 单元内，通过 &amp;ldquo;weak/strong dance&amp;rdquo; 的变体来避免循环引用。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-objective-c&#34; data-lang=&#34;objective-c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 方案一：复杂的 Block 自引用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;- (&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;)&lt;span style=&#34;color:#a6e22e&#34;&gt;executeRetryableTask:&lt;/span&gt;(RetryableApiCallBlock)apiCall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#a6e22e&#34;&gt;maxRetries:&lt;/span&gt;(NSInteger)maxRetries
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#a6e22e&#34;&gt;retryInterval:&lt;/span&gt;(NSTimeInterval)retryInterval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#a6e22e&#34;&gt;completion:&lt;/span&gt;(RetryCompletionBlock)completion {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;__block&lt;/span&gt; NSInteger currentRetryCount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;__block&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;__weak&lt;/span&gt; weakAttemptBlock)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// 弱引用指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;attemptBlock)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// 局部变量，存储在栈上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attemptBlock &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;strongAttemptBlock)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; weakAttemptBlock; &lt;span style=&#34;color:#75715e&#34;&gt;// 试图从弱引用恢复强引用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        apiCall(&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;id&lt;/span&gt; responseObject) { &lt;span style=&#34;color:#75715e&#34;&gt;/* ... 成功 ... */&lt;/span&gt; }, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;(NSError &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;error) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            currentRetryCount&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (currentRetryCount &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; maxRetries) { &lt;span style=&#34;color:#75715e&#34;&gt;/* ... 最终失败 ... */&lt;/span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryInterval &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; NSEC_PER_SEC)), dispatch_get_main_queue(), &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (strongAttemptBlock) { &lt;span style=&#34;color:#75715e&#34;&gt;// Bug 所在：strongAttemptBlock 在此会是 nil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;                        strongAttemptBlock();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    weakAttemptBlock &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; attemptBlock;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attemptBlock();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;方案二简单的异步递归&#34;&gt;方案二：简单的异步递归&lt;/h4&gt;
&lt;p&gt;这种方案利用简单的递归调用，通过参数传递状态，代码直观且健壮。&lt;/p&gt;</description>
    </item>
    <item>
      <title>短剧播放器管理设计与实现</title>
      <link>https://atomicink.github.io/posts/short-drama-player-manager/</link>
      <pubDate>Fri, 30 May 2025 16:38:50 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/short-drama-player-manager/</guid>
      <description>&lt;p&gt;从你目前“只能在 ViewController 的滚动逻辑里判断，AVPlayer 只会每个 PlayerView 持有一个”的状态，到能够设计并实现 &lt;code&gt;ShortDramaPlayManager&lt;/code&gt; 这样的复杂度和抽象程度，确实需要一个系统性的提升过程。&lt;/p&gt;
&lt;p&gt;这不是一蹴而就的，而是经验、知识和刻意练习的积累。下面我将从几个方面为你剖析如何提升：&lt;/p&gt;
&lt;h3 id=&#34;1-深化对-objective-c-和-ios-sdk-的理解-不仅仅是会用&#34;&gt;1. 深化对 Objective-C 和 iOS SDK 的理解 (不仅仅是“会用”)&lt;/h3&gt;
&lt;p&gt;你列出的核心技能是基础，但要达到 &lt;code&gt;ShortDramaPlayManager&lt;/code&gt; 的水平，需要对这些技能有更深的理解和应用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective-C Runtime&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;KVO (Key-Value Observing)&lt;/strong&gt;: &lt;code&gt;ShortDramaPlayManager&lt;/code&gt; 通过 KVO 监听 &lt;code&gt;UIScrollView&lt;/code&gt; 的 &lt;code&gt;contentOffset&lt;/code&gt; 和 &lt;code&gt;AVPlayer&lt;/code&gt; 的 &lt;code&gt;timeControlStatus&lt;/code&gt;。你需要理解 KVO 的工作原理、如何正确添加和移除观察者（注意 &lt;code&gt;context&lt;/code&gt; 的使用、&lt;code&gt;@try-@catch&lt;/code&gt; 避免崩溃）、以及潜在的陷阱（如父类也观察了同一个属性、忘记移除观察者导致的崩溃）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息传递&lt;/strong&gt;: 虽然不直接体现在这个 Manager 中，但理解消息传递机制有助于你设计更灵活的接口和回调。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blocks&lt;/strong&gt;: Manager 中大量使用了 block（例如 &lt;code&gt;NSTimer&lt;/code&gt; 的 target-action 模式可以用 block 替代，GCD 的使用）。你需要熟练掌握 block 的语法、内存管理（&lt;code&gt;__weak&lt;/code&gt;, &lt;code&gt;__strong&lt;/code&gt; self）、以及作为参数和返回值的使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存管理 (ARC/MRC)&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;强引用循环 (Retain Cycles)&lt;/strong&gt;: &lt;code&gt;NSTimer&lt;/code&gt; 持有 target，如果 target 也强持有 timer，就会循环引用。KVO、&lt;code&gt;NSNotificationCenter&lt;/code&gt; 的观察者也可能导致循环引用。Manager 中通过在 &lt;code&gt;dealloc&lt;/code&gt; 和特定时机移除观察者、停止 timer 来避免。你需要培养对潜在循环引用的敏感度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对象生命周期&lt;/strong&gt;: 理解对象的创建、持有、释放过程，尤其是在集合类（&lt;code&gt;NSDictionary&lt;/code&gt;, &lt;code&gt;NSMutableSet&lt;/code&gt;）中管理对象时。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iOS SDK&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AVFoundation&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AVPlayer&lt;/code&gt; vs &lt;code&gt;AVPlayerItem&lt;/code&gt; vs &lt;code&gt;AVPlayerLayer&lt;/code&gt;&lt;/strong&gt;: Manager 的核心是共享一个 &lt;code&gt;AVPlayer&lt;/code&gt; 实例，通过切换 &lt;code&gt;AVPlayerItem&lt;/code&gt; 来播放不同视频，并将 &lt;code&gt;AVPlayer&lt;/code&gt; 关联到不同 &lt;code&gt;VideoPlayerView&lt;/code&gt; 的 &lt;code&gt;AVPlayerLayer&lt;/code&gt;。这是为了性能和资源优化。你需要理解这三者的关系和各自职责。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AVPlayerItem&lt;/code&gt; 状态和通知&lt;/strong&gt;: 如何预加载 &lt;code&gt;AVPlayerItem&lt;/code&gt; (&lt;code&gt;preparePlayerView:withURL:&lt;/code&gt;)，如何监听播放结束 (&lt;code&gt;AVPlayerItemDidPlayToEndTimeNotification&lt;/code&gt;) 并处理（如重播）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;UIScrollView&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;contentOffset&lt;/code&gt;, &lt;code&gt;contentInset&lt;/code&gt;, &lt;code&gt;bounds&lt;/code&gt;&lt;/strong&gt;: 精确计算视图可见性、相对位置的基础。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delegate vs KVO&lt;/strong&gt;: Manager 选择 KVO 监听 &lt;code&gt;contentOffset&lt;/code&gt;，而不是依赖 delegate。这使得 Manager 可以独立于 ViewController，并且可以同时管理多个 &lt;code&gt;UIScrollView&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NSNotificationCenter&lt;/code&gt;&lt;/strong&gt;: 用于应用生命周期事件（前后台切换）的响应，以及可能的内部事件通知。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NSTimer&lt;/code&gt;&lt;/strong&gt;: 用于实现延迟操作（滚动停止后播放、滚动检测）。注意 timer 的精度问题、RunLoop 模式，以及及时 &lt;code&gt;invalidate&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;UIView&lt;/code&gt; 坐标转换&lt;/strong&gt;: &lt;code&gt;convertRect:toView:&lt;/code&gt; 和 &lt;code&gt;convertPoint:fromView:&lt;/code&gt; 对于判断视图在屏幕上的位置至关重要 (&lt;code&gt;isPlayerViewInReasonableRange&lt;/code&gt;)。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-学习和应用设计模式与原则&#34;&gt;2. 学习和应用设计模式与原则&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ShortDramaPlayManager&lt;/code&gt; 体现了多种设计模式和原则：&lt;/p&gt;</description>
    </item>
    <item>
      <title>YYWebImage 在 Masonry 宽度不符预期的问题</title>
      <link>https://atomicink.github.io/posts/yywebimage-zai-masonry-kuan-du-bu-fu-yu-qi-de-wen-ti/</link>
      <pubDate>Tue, 29 Apr 2025 15:50:05 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/yywebimage-zai-masonry-kuan-du-bu-fu-yu-qi-de-wen-ti/</guid>
      <description>&lt;h3 id=&#34;问题场景&#34;&gt;问题场景&lt;/h3&gt;
&lt;p&gt;假设我们有如下布局代码，目标是在一个容器 &lt;code&gt;logoTitleContainer&lt;/code&gt; 内居中显示一个 Logo 图片 &lt;code&gt;_appLogoImageView&lt;/code&gt;，并指定其高度为 20 points：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-objectivec&#34; data-lang=&#34;objectivec&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UIView &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;logoTitleContainer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [[UIView alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logoTitleContainer.backgroundColor &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [UIColor clearColor];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[_containerView addSubview:logoTitleContainer];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[logoTitleContainer mas_makeConstraints:&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;(MASConstraintMaker &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;make) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.centerX.equalTo(_containerView);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.top.mas_offset(&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.height.mas_equalTo(&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.width.mas_equalTo(&lt;span style=&#34;color:#ae81ff&#34;&gt;192&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Logo ImageView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;_appLogoImageView &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [[UIImageView alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_appLogoImageView.contentMode &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; UIViewContentModeScaleAspectFit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[logoTitleContainer addSubview:_appLogoImageView];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[_appLogoImageView mas_makeConstraints:&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;(MASConstraintMaker &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;make) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.height.mas_equalTo(&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.centerY.equalTo(logoTitleContainer);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.centerX.equalTo(logoTitleContainer);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make.width.lessThanOrEqualTo(logoTitleContainer);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 加载网络图片 (原始尺寸 210x44 像素)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;NSURL &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;imageUrl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [NSURL URLWithString:&lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;YOUR_IMAGE_URL_HERE&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[_appLogoImageView yy_setImageWithURL:imageUrl placeholder:nil];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;预期效果：&lt;/strong&gt; &lt;code&gt;_appLogoImageView&lt;/code&gt; 的高度被固定为 20 points，&lt;code&gt;ScaleAspectFit&lt;/code&gt; 模式会根据图片原始宽高比（210/44 ≈ 4.77）计算出适应此高度的宽度（20 * 4.77 ≈ 95.4 points），图片应该以此尺寸显示在容器中心。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Protocol 实践思维养成</title>
      <link>https://atomicink.github.io/posts/protocol/</link>
      <pubDate>Wed, 02 Apr 2025 16:45:42 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/protocol/</guid>
      <description>&lt;p&gt;很多开发者（包括经验丰富的）都会遇到类似情况：明明知道某个技术概念（比如 Protocol），但在实际编码时却想不起来用。这其实是一个非常普遍的学习阶段现象。&lt;/p&gt;
&lt;h3 id=&#34;一为什么知道-protocol-却想不起用&#34;&gt;&lt;strong&gt;一、为什么知道 Protocol 却想不起用？&lt;/strong&gt;&lt;/h3&gt;
&lt;h3 id=&#34;1-知识与应用存在断层&#34;&gt;1. &lt;strong&gt;知识与应用存在断层&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;知道 ≠ 会用&lt;/strong&gt;：学习技术概念时，我们往往停留在&amp;quot;知道它是什么&amp;quot;，但缺乏&amp;quot;什么时候用它&amp;quot;的直觉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：就像知道螺丝刀的存在，但看到松动的螺丝时，第一反应可能是用手去拧，而不是找螺丝刀。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-惯性思维主导&#34;&gt;2. &lt;strong&gt;惯性思维主导&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;习惯性用 &lt;code&gt;if-else&lt;/code&gt;&lt;/strong&gt;：面对具体问题时，大脑会优先调用最熟悉的解决方案（比如条件分支），而不是评估所有可能性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;思维路径&lt;/strong&gt;：&lt;em&gt;&amp;ldquo;我需要判断不同类 → 用 &lt;code&gt;isKindOfClass:&lt;/code&gt; → 写一堆 &lt;code&gt;if-else&lt;/code&gt;&amp;quot;&lt;em&gt;而不是：&lt;/em&gt;&amp;ldquo;这些类有共同行为 → 应该抽象成协议&amp;rdquo;&lt;/em&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-缺乏设计模式的敏感度&#34;&gt;3. &lt;strong&gt;缺乏设计模式的敏感度&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Protocol 的本质是&lt;strong&gt;抽象行为约定&lt;/strong&gt;，但初学者往往更关注具体实现细节（比如如何写方法），而忽略抽象设计。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;4-对-protocol-的理解不够深刻&#34;&gt;4. &lt;strong&gt;对 Protocol 的理解不够深刻&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;可能你目前对 Protocol 的认知停留在：
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;它是声明方法的列表&amp;rdquo;（表面）&lt;/li&gt;
&lt;li&gt;而不是：&amp;ldquo;它是解耦和扩展架构的工具&amp;rdquo;（本质）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;二如何培养用-protocol的思维&#34;&gt;&lt;strong&gt;二、如何培养「用 Protocol」的思维？&lt;/strong&gt;&lt;/h3&gt;
&lt;h3 id=&#34;1-建立行为抽象的条件反射&#34;&gt;1. &lt;strong&gt;建立「行为抽象」的条件反射&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;遇到以下场景时，强制自己思考 Protocol&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;多个类有相同的方法名（比如你的 &lt;code&gt;incrementShareCount&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;需要判断对象是否能响应某个方法（&lt;code&gt;respondsToSelector:&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;代码中出现 &lt;code&gt;if ([obj isKindOfClass:[XXX class]])&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;需要跨模块通信（如 Delegate 模式）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;口诀&lt;/strong&gt;：&lt;em&gt;&amp;ldquo;重复方法？抽象它！类型判断？协议化！跨类调用？定义协议！&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-从模仿优秀代码开始&#34;&gt;2. &lt;strong&gt;从模仿优秀代码开始&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;研究 Apple 官方代码&lt;/strong&gt;：iOS SDK 中大量使用 Protocol（如 &lt;code&gt;UITableViewDataSource&lt;/code&gt;, &lt;code&gt;NSCopying&lt;/code&gt;）。思考为什么这些场景要用 Protocol。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-objectivec&#34; data-lang=&#34;objectivec&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 为什么 UITableView 不直接提供数据，而是通过 DataSource 协议？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 答案：解耦！UITableView 不需要知道数据来源是数组、CoreData 还是网络。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-重构练习将现有代码改为-protocol-实现&#34;&gt;3. &lt;strong&gt;重构练习：将现有代码改为 Protocol 实现&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;具体步骤&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>关于我</title>
      <link>https://atomicink.github.io/about/</link>
      <pubDate>Wed, 01 Jan 2025 00:00:00 +0800</pubDate>
      <guid>https://atomicink.github.io/about/</guid>
      <description>&lt;p&gt;你好，我是一个对技术充满热情的人。
这里存放一些学习笔记。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ijkplayer iOS设置代理</title>
      <link>https://atomicink.github.io/posts/ijkplayer-ios-she-zhi-dai-li/</link>
      <pubDate>Tue, 04 Jun 2024 16:37:02 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/ijkplayer-ios-she-zhi-dai-li/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    IJKFFOptions *op = [IJKFFOptions optionsByDefault];
    [op setFormatOptionValue:@&amp;#34;http://127.0.0.1:80&amp;#34; forKey:@&amp;#34;http_proxy&amp;#34;];
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Pod 关于 unknown UUID 警告</title>
      <link>https://atomicink.github.io/posts/pod-guan-yu-unknown-uuid-jing-gao/</link>
      <pubDate>Mon, 04 Mar 2024 16:39:21 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/pod-guan-yu-unknown-uuid-jing-gao/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[!] `&amp;lt;PBXSourcesBuildPhase UUID=`BC2BAE431A89F1450060D863`&amp;gt;` attempted to initialize an object with an unknown UUID. `38F3FD552A2F25DF00AEAAC4` for attribute: `files`. This can be the result of a merge and the unknown UUID is being discarded.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个错误通常是由于合并代码时导致的，可能会导致未知的UUID被丢弃。解决方法如下：&lt;/p&gt;
&lt;p&gt;从CocoaPods中解除你的项目。删除Xcode项目中所有CocoaPods的痕迹。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ pod deintegrate
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再次安装Pod。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ pod install
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>UITextView限制字数</title>
      <link>https://atomicink.github.io/posts/uitextview-xian-zhi-zi-shu/</link>
      <pubDate>Tue, 15 Dec 2015 00:00:00 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/uitextview-xian-zhi-zi-shu/</guid>
      <description>&lt;p&gt;一开始认为UITextView限制字数很简单，在delegate里处理一下shouldChangeTextInRange就行了：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;//const NSInteger kMaxLength = 100;
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    return textView.text.length + text.length - range.length &amp;lt;= kMaxLength;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;没想到在使用拼音输入法的联想功能时并不触发这个方法。只好在textViewDidChange里强行限制了：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;- (void)textViewDidChange:(UITextView *)textView {
    if(textView.text.length &amp;gt; kMaxLength) {
        textView.text = [textView.text substringToIndex:kMaxLength];
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>命令行打包ipa</title>
      <link>https://atomicink.github.io/posts/ming-ling-xing-da-bao-ipa/</link>
      <pubDate>Sat, 31 Oct 2015 00:00:00 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/ming-ling-xing-da-bao-ipa/</guid>
      <description>&lt;p&gt;入职新公司，公司的自动打包环境最近出问题了，只好手动打包，命令如下：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;xcodebuild -scheme scheme名 -sdk iphoneos -configuration AppStoreDistribution archive -archivePath $PWD/build/app名.xcarchive
xcodebuild -exportArchive -archivePath $PWD/build/app名.xcarchive -exportPath $PWD/build -exportProvisioningProfile &amp;#34;Provisioning名&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意：以前流行的xcrun PackageApplication现在是无法使用的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>NSOrderedSet的崩溃问题</title>
      <link>https://atomicink.github.io/posts/nsorderedset-de-beng-kui-wen-ti/</link>
      <pubDate>Fri, 13 Mar 2015 00:00:00 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/nsorderedset-de-beng-kui-wen-ti/</guid>
      <description>&lt;p&gt;最近把项目里CoreDataModel的一个一对多的关系改为有序的，对象的class因此从NSSet变为NSOrderedSet。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@property (nonatomic, retain) NSOrderedSet *myFlowDetail;

- (void)addMyFlowDetailObject:(MyFlowDetailEntity *)value;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用中却发现向NSOrderedSet里添加对象时会崩溃，经查询发现似乎是一个Apple从2011年到现在都没解决的bug。&lt;/p&gt;
&lt;p&gt;临时解决方法是给这个类添加一个category覆盖上述方法：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;- (void)addMyFlowDetailObject:(MyFlowDetailEntity *)value
{
    NSMutableOrderedSet *flowDetail = [[NSMutableOrderedSet alloc] initWithOrderedSet:self.myFlowDetail];
    [flowDetail addObject:value];
    self.myFlowDetail = flowDetail;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;参考：&lt;a href=&#34;http://stackoverflow.com/questions/7385439/exception-thrown-in-nsorderedset-generated-accessors&#34;&gt;Exception thrown in NSOrderedSet generated accessors&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>《把你的英语用起来》阅读笔记</title>
      <link>https://atomicink.github.io/posts/english-notes/</link>
      <pubDate>Sat, 03 Aug 2013 13:24:38 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/english-notes/</guid>
      <description>&lt;p&gt;&lt;strong&gt;核心策略&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;专注学习：&lt;/strong&gt; 避免社交网络等干扰。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自我监控：&lt;/strong&gt; 通过记笔记追踪进度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;循序渐进：&lt;/strong&gt; 从小目标开始，逐步增加难度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;立即行动：&lt;/strong&gt; 克服拖延，想到就做。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正面激励：&lt;/strong&gt; 采用奖励机制，避免自我批评。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;基本原则&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;告别电视剧：&lt;/strong&gt; 减少被动娱乐时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;晨间学习：&lt;/strong&gt; 将学习时间调整至精力更充沛的早上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间管理：&lt;/strong&gt; 高效结合零碎时间与整块时间。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;听力提升&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础发音：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;赖世雄音标：&lt;/strong&gt; 看书听CD，大声跟读模仿。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;American Pronunciation Workshop &amp;amp; 剖面&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;American Accent Training&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进阶听力与模仿 (EnglishPod)：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前提：&lt;/strong&gt; 确认已超越VOA慢速水平。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计划：&lt;/strong&gt; 制定每日学习与复习计划。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;步骤：&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;听讲解：&lt;/strong&gt; 1-2遍，理解为主。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;听对话：&lt;/strong&gt; 专注听约9遍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跟读语调：&lt;/strong&gt; 模仿录音韵律，哼唱跟读。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跟读练习：&lt;/strong&gt; 先看文本跟读3-4遍，再脱稿连续跟读约9遍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;笔记与复习：&lt;/strong&gt; 记录生词重点，利用零碎时间记忆。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强化练习：&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;录音对比：&lt;/strong&gt; 挑选喜欢的课文录音，模仿语气，与原音穿插对比听9次。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;迭代优化：&lt;/strong&gt; 不满意则重复跟读与录音步骤。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;泛听材料：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audiobook (有声读物)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;语法巩固&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心教材：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;《语法俱乐部》：&lt;/strong&gt; 精读至少5遍，结合大量阅读实践，分阶段（初学、数月后、隔年后）反复研读，打好内功基础。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;补充练习：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;《剑桥中级英语语法》（英文版）：&lt;/strong&gt; 在《语法俱乐部》后使用，通过真实语料库例句检验和巩固语法知识。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;阅读方法 (透析法)&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;控制查词：&lt;/strong&gt; 每2页最多查1个生词。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每日复习：&lt;/strong&gt; 每天花5分钟复习近几天查过的词。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集中突破 (可选)：&lt;/strong&gt; 如进行“7天行动”，则每天读40页，坚持7天。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读后回顾：&lt;/strong&gt; 阅读完成后进行总结。&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>Windows下编译WPA Supplicant</title>
      <link>https://atomicink.github.io/posts/windows-xia-bian-yi-wpa-supplicant/</link>
      <pubDate>Sat, 15 Jun 2013 00:00:00 +0800</pubDate>
      <guid>https://atomicink.github.io/posts/windows-xia-bian-yi-wpa-supplicant/</guid>
      <description>&lt;h1 id=&#34;下载winpcap&#34;&gt;下载WinPcap&lt;/h1&gt;
&lt;p&gt;下载&lt;code&gt;WpdPack_4_0_2.zip&lt;/code&gt;，解压到&lt;code&gt;C:\dev\WpdPack&lt;/code&gt;。&lt;/p&gt;
&lt;h1 id=&#34;编译openssl&#34;&gt;编译OpenSSL&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;下载&lt;code&gt;openssl-1.0.1e.tar.gz&lt;/code&gt;并解压。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;\include\openssl\x509v3.h&lt;/code&gt;里添加：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#ifdef OPENSSL_SYS_WIN32
    /* Under Win32 these are defined in wincrypt.h */  
#undef X509_NAME
#undef X509_CERT_PAIR
#undef X509_EXTENSIONS
#endif
&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;安装ActivePerl&lt;/li&gt;
&lt;li&gt;打开VS命令提示行，进入OpenSSL路径，依次输入以下命令：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;perl Configure VC-WIN32 no-asm --prefix= C:\dev\OpenSSL
ms\do_ms
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak install
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;编译wpa-supplicant&#34;&gt;编译WPA Supplicant&lt;/h1&gt;
&lt;p&gt;下载&lt;code&gt;wpa_supplicant-0.7.3.tar.gz&lt;/code&gt;并解压。
用VS2008打开&lt;code&gt;vs2005\wpa_supplicant.sln&lt;/code&gt;，编译即可。&lt;/p&gt;
&lt;h1 id=&#34;问题与解决&#34;&gt;问题与解决&lt;/h1&gt;
&lt;p&gt;OpenSSL的宏定义和VS的wincrypt.h的宏定义冲突，需要按上述方法取消宏定义。
wpa_supplicant-2.0在Windows下编译有很多问题，用0.7.3版可以编译。
VS2005在编译时会提示“调试信息损坏,请重新编译模块”，经查询是VS2005自身的bug，改用VS2008可编译。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
