数字夜话的博客

开始好好写博客.

IOS8系列

IOS8系列学习目录整理

学习路线

  1. IOS8 Swift语言与objective-c
  2. IOS8 lib库学习
  3. XCode IDE介绍
  4. Test单元测试
  5. 第三方框架
  6. 软件工程
  7. 用户UI设计

IOS8语言学习

IOS语言分为IOS8前的obcjective-c和IOS8后的Swift语言。见Swift语法_学习系列

IOS8 lib库学习

与之前的sdk版本相似,sdk内容主要分以下几部分: "工程目录结构" "模拟器"



结构描述
framework由apple工程师封装的框架
developerframeworks由apple工程师封装的测试框架
user/includeapple常用的一些c/c++函数
user/local/includeapple对模拟器支持的一些c/c++

从IOS的系统层次划分学习单元。分为4层62个框架与其他框架组合11个,总共73个框架。这些框架中可以归纳的知识点包括:图形、流媒体、网络与数据等等。

系统层次 框架名 描述
cocoa touch layer(10) UIKit
AddressBookUI
EventKitUI
Twitter
PhotosUI
NotificationCenter
MessageUI
MapKit
iAd
GameKit
media layer(22) AssetsLibrary
AudioToolBox
AudioUnit
AVFoundation
CoreAudio
CoreGraphics
CoreImage
CoreMIDI
CoreText
CoreVideo
GameController
GLKit
ImageIO
MediaAccessibility
MediaPlayer
Metal
OpenAL
OpenGLES
Photos
QuartzCore
SceneKit
SpriteKit
core Services layer(24) Accounts
AddressBook
AdSupport
CFNetWork
CloudKit
CoreData
CoreFoundation
CoreLocation
CoreMedia
CoreMotion
CoreTelephony
EventKit
Foundation
HomeKit
javaScriptCore
MobileCoreServices
MultipeerConnectivity
NewsstandKit
Passkit
QuickLook
Social
StoreKit
SystemConfiguration
UIAutomation
core OS layer(6) Accelerate
CoreBluetooth
ExternalAccessory
LocalAuthentication
Security
system
其他framwork(11) ApplicationServices
AVKit
webKit
VideoToolBox
SafariServices
pushKit
notificationUI
IOKit
healthKit
GSS
MediaToolbox

流媒体基本信息

术语表(Glossary)

5.1 环绕声(5.1 Surround Sound):一个环绕声扬声器配置包括5个扬声器位于一个圆周的具体位置和一个低音炮(”.1”).扬声器频道同在位于:左、中、右、左环绕、右环绕和LFE(低频效果)。

8.24 有时候写作Q8.24 或者fx8.24.定点采样大小(替代32位浮点采样)被当作标准的音频采样类型,来处理线性pcm音频。在8.24音频样本中,左边8位代表整数基点,右边24位代表小数基点。

AAC 高级音频编码(advanced audio coding):一个压缩,有损的感知编码方案。1997年ISO/IEC 13818-7将AAC作为MPEG-2的一部分,成为MPEG-2 AAC。并在MPEG-4中做了增强,MPEG-4 AAC。根据发表在ISO/IEC JTC1/SC29/WG11, N2006 上的结果看,MPEG-2 AAC比MPEG-1,layer3(mp3)在同个位速率(bit rate)上有更好的音频质量。MPEG-4 AAC扩展了MPEG-2 AAC 的额外编码工具。

AC-3 它是杜比公司开发的新一代家庭影院多声道数字音频系统。杜比定向逻辑系统是一个模拟系统。它的四个声道是从编码后的两个声道分解出来的,因此难免有分离度不佳、信噪比不高,对环绕声缺乏立体感,并且环绕声的频带窄等缺点。AC(Audio Coding)指的是数字音频编码,它抛弃了模拟技术,采用的是全新的数字技术。

active 在iOS中用于在播放或者录音时描述audio session的状态是否可持续。比较inactive。

ADC 模拟数字转换器(英语:Analog-to-digital converter, ADC, A/D or A to D)是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。一个模拟数字转换器可以提供信号用于测量。与之相对的设备成为数字模拟转换器。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。然而,有一些模拟数字转换器并非纯的电子设备,例如旋转编码器,也可以被视为模拟数字转换器。数字信号输出可能会使用不同的编码结构。通常会使用二进制二补数(也称作“补码”)进行表示,但也有其他情况,例如有的设备使用格雷码(一种循环码).

PCM:脉冲编码调制(英文:Pulse-code modulation,缩写:PCM)是一种模拟信号的数字化方法。PCM将信号的强度依照同样的间距分成数段,然后用独特的数字记号(通常是二进制)来量化。PCM常被用于数字电信系统上,也是电脑和红皮书中的标准形式。在数字视频中它也是标准,例如使用 ITU-R BT.601。但是PCM并不流行于诸如DVD或DVR的消费性商品上,因为它需要相当大的比特率(DVD格式虽然支持PCM,不过很少使用);与之相较,压缩过的音频较符合效率。不过,许多蓝光光盘使用PCM作音频编码。非常频繁地,PCM编码以一种串行通信的形式,使数字传讯由一点至下一点变得更容易——不论在已给定的系统内,或物理位置。

Differential(差异)或Delta PCM(DPCM)纪录的是目前的值与前一个值的差异值。与相等的PCM比较,这种编码只需要25%的比特数。

ADPCM是DPCM的变形,给定一个噪讯比,以节省量化密度的方式,允许更大程度的节省带宽。

AES/EBU的全称是Audio Engineering Society/European Broadcast Union(音频工程师协会/欧洲广播联盟),现已成为专业数字音频较为流行的标准。大量民用产品和专业音频数字设备如CD机、DAT、MD机、数字调音台、数字音频工作站等都支持AES/EBU。它们已经颁布了许多关于数字音频的重要标准。

AES-3 一个在1992年发布的,由AES定义的数字音频传输标准。也叫做AES/EBU接口,等同于IEC 60958 第四部分。AES-3标准包括不同的物理链接:平衡双绞线,非平衡同轴电缆和光纤。AES-3的诞生来源于S/PDIF (Sony/Phillips Digital Interface)标准。数字音频接口协议,可用XLR线传输两路数字音频信号,单向传输,也可用25Pin(25针)线缆传输8路信号,双向传输.

AES/EBU: AES/EBU标准 AES/EBU是一种通过基于单根绞合线对来传输数字音频数据的串行位传输协议。它无须均衡即可在长达100m的距离上传输数据,如果均衡,可以传输更远距离。它提供两个信道的音频数据(最高24比特量化),信道是自动计时和自同步的。它也提供了传输控制的方法和状态信息的表示(channel status bit)和一些误码的检测能力。它的时钟信息是由传输端控制,来自AES/EBU的位流。它的三个标准采样率是32kHz、44.1kHz、48kHz,当然许多接口能够工作在其它不同的采样率上。 AES/EBU提供“专业”和“消费”两种模式。它们两者最大的不同在于信道状态位格式的提供上。专业模式的状态位格式里包括数字信道的源和目的地址、日期时间码、采样点数、字节长度和其它信息。消费模式包括的东西就比较少,但包含了拷贝保护信息。另外,AES/EBU标准提供“用户数据”,在它的位流里包含用户说明(例如厂商说明等)。图1是AES/EBU专业格式24字节信道状态数据块的一部分。 AES/EBU的普通物理连接媒质有:(1)平衡或差分连接,使用XLR(卡侬)连接器的三芯话筒屏蔽电缆,参数为阻抗110Ω,电平范围0.2V~5Vpp,抖动为±20ns。(2)单端非平衡连接,使用RCA插头的音频同轴电缆。(3)光学连接,使用光纤连接器。

集合设备aggregate device,一组由软件程序控制两个或者多个音频设备互相连接构成的一个单个设备。

音频交换文件格式(Audio Interchange File Format,缩写为AIFF)一种音频格式用于个人电脑和其他电子音频设备存储音频数据。这种格式由苹果公司于1988年在美商艺电的交换档案格式(Interchange File Format,缩写 IFF,广泛使用于Amiga系统)基础上开发而成,并且它多被用在苹果公司的OS X操作系统。在一个标准的AIFF文件中的音频是线性PCM(pulse-code modulation)。还有一种被称为AIFF-C或AIFC的经过压缩的变体,with various defined compression codecs。标准AIFF格式与SDII和WAV一并被认为是专业登记的视频音频编辑应用和的领导性格式,并且与广为人知的有损格式MP3相比,它并未经过压缩。与其它的未压缩无损音频格式相比,AIFF会占用比MP3更多的磁盘空间。在立体声的44.1 kHz采样率和16 bits采样深度的条件下,这个差额大约是每分钟10MB。

音频压缩交换文件(Audio Interchange File Format Extension for Compression),一个AIFF的扩展,他可以对数据进行压缩或者不压缩。

混淆aliasing,也称为混叠。在声音采样来说,混淆是指在进行取样时,和一个正确频率一起生成的一个错误频率,这时混淆会产生杂音。对于图像生成来说,混淆会产生锯齿状的边缘或者梯阶效果。当采样率低于奈奎斯特频率(即被采样频率的一半)时,被采样波形周期内将少于2个采样,在这种情况下,采样点在播放时将不能重建原信号,而会比原信号的频率低,具体的差异遵循这一公式:新频率=采样频率-被采样信号频率,例如,当以采样率为44.1kHz对一个26kHz的频率进行取样时,ADC读取的将是44.1-26=18.1kHz。[1]

奈奎斯特频率(Nyquist frequency)是离散信号系统采样频率的一半,因哈里·奈奎斯特(Harry Nyquist)或奈奎斯特-香农采样定理得名。采样定理指出,只要离散系统的奈奎斯特频率高于被采样信号的最高频率或带宽,就可以避免混叠现象。

头部相关传输函数(Head Related Transfer Functions,缩写:HRTF)又称为ATF(anatomical transfer function),是一种音效定位算法。

HRTF是一组滤波器,系利用HD ITD(Interaural Time Delay)、IAD(Interaural Amplitude Difference)和耳廓频率振动等技术产生立体音效,使声音传递至人耳内的耳廓,耳道和鼓膜时,聆听者会有环绕音效之感觉,通过DSP,HRTF可实时处理虚拟世界的音源。

平均码率通常是指数字音乐或者视频的平均码率,可以简单的认为等于文件大小除以播放时间。例如常用的RMVB在压缩电影时常常设定视频平均码率为450kbps,则平均每秒占用约55千字节,这样可以估算10分钟的视频大小约为55KB6010=33MB,2小时的视频则约为400MB。码率并不是衡量音频/视频质量的唯一标准,格式、图像大小、音频采样率、音频分辨率等因素也是很重要的指标。由于在实际编码中,会根据图像/音频的复杂程度,而对码率进行一些调整,以达到最好的控制文件大小及质量,因此,最终的平均码率并不能在编码之前确定下来,波动幅度较大。为了从一定程度解决这个问题,二次编码方式诞生了。它在第一次编码时不进行实际编码运算,仅仅是计算码率,第二次利用这一计算结果为基础,根据设定值进行调整,并最终编码。除了平均码率之外,最高码率,或者叫码率峰值,也是与码率有关的一个参数。当码率峰值高过处理器所能处理的强度时,可能会造成播放延迟。以上概念是针对可变码率编码(VBR)而言的,实际上平均码率编码方式理论和此完全不同.

固定码率(英语:Constant bitrate,简称CBR)这是一个用来形容通信服务质量(QoS,Quality of Service)的术语。和该词相对应的词是可变码率或可变比特率(英文variable bit rate,缩写VBR)。当形容编解码器的时候,CBR编码指的是编码器的输出码率(或者解码器的输入码率)应该是固定制(常数)。当在一个带宽受限的信道中进行多媒体通讯的时候CBR是非常有用的,因为这时候受限的是最高码率,CBR可以更容易的使用这样的信道。但是CBR不适合进行存储,因为CBR将导致没有足够的码率对复杂的内容部分进行编码(从而导致质量下降),同时在简单的内容部分会浪费一些码率。大部分编码方案的输出都是可变长的码字,例如霍夫曼编码或者游程编码(run-length coding),这使得编码器很难做到完美的CBR。编码器可以通过调整量化(进而调整编码质量)来部分的解决这个问题,如果同时使用填充码来完美的达到CBR。(有时候,CBR也指一种非常简单的编码方案,比如将一个16位精度的音频数据流通过抽样得到一个8位精度的数据流).

可变码率(英语:Variable bitrate,简称VBR)这是一个用来形容通信服务质量(QoS for Quality of Service)的术语。和该词相对应的词是固定码率或固定比特率,英文constant bit rate,缩写CBR。例如,使用MP3格式的音频编解码器,音频文件可以以8~320kbps的可变码率进行压缩,得到相对小的文件来节约存储空间。MP3格式的文件格式是.mp3。当形容编解码器的时候,VBR编码指的是编码器的输出码率(或者解码器的输入码率)可以根据编码器的输入源信号的复杂度自适应的调整,目的是达到保持输出质量保持不变而不是保持输出码率保持不变。VBR适用于存储(不太适用于流式传输),可以更有效地利用有限的存储空间:用比较多的码字对复杂度高的段进行编码,用比较少的码字对复杂度低的段进行编码。像Vorbis这样的编解码器和几乎所有的视频编解码器内在的都是VBR的。.mp3文件也可以以VBR的方式进行编码。

AVI是英语Audio Video Interleave(“音频视频交织”或译为“音频视频交错”)的首字母缩写,由微软在1992年11月推出的一种多媒体文件格式,用于对抗苹果Quicktime的技术。现在所说的AVI多是指一种封装格式。AVI的文件结构、分为“头部”,“主体”和“索引”三部分。主体中图像数据和声音数据是交互存放的。从尾部的索引可以索引跳到自己想放的位置。AVI将视频和音频封装在一个文件里,其顺序是:若干视频帧(Video Frame)之后接着若干音频帧(Audio Frame),再然后是视频帧、音频帧,故名为“音频视频交织”,意即音频和视频按帧交错排列,以此达到音频同步于视频播放的效果。和DVD视频格式一样,AVI文件支持多视频流和音频流,虽然这些功能很少使用。大多数AVI文件还支持由Matrox OpenDML集团于1996年2月开发的格式后缀。这些文件非正式的称为“AVI 2.0”,并得到微软的支持。

带宽(英语:Bandwidth)指信号所占据的频带宽度;在被用来描述信道时,带宽是指能够有效通过该信道的信号的最大频带宽度。对于模拟信号而言,带宽又称为频宽,以赫兹(Hz)为单位。例如模拟语音电话的信号带宽为3400Hz,一个PAL-D电视频道的带宽为8MHz(含保护带宽)。对于数字信号而言,带宽是指单位时间内链路能够通过的数据量。例如ISDN的B信道带宽为64Kbps。由于数字信号的传输是通过模拟信号的调制完成的,为了与模拟带宽进行区分,数字信道的带宽一般直接用波特率或符号率来描述。

采样率(sample rate):或称“采样速率”,是每秒内采样点(sample)的密集程度,单位是赫兹(Hz)。

采样深度(sample depth):或称“采样精度”,就是对采样点的采样精确度。单位是比特(bit)。

比特率(Bit rate):亦称“位速率”,是单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信道容量、最大吞吐量和数字带宽容量的同义词,根据位深的幅度分辨率,量化误差.多媒体行业在指音频或者视频在单位时间内的数据传输率时通常使用码流或码率,单位是kbps(千位每秒)。在数字多媒体领域,比特率代表了信息的数量,更详细地说,存储了一个记录的每单位时间。比特率和以下几个因素相关: 原始物质也许取样在不同的频率里 取样可能使用了不同数量的比特 数据可能按照不同的方式编码 信息可能用不同的算法或不同的程度进行数字压缩。

位深(bit depth):采样方案,每个采样的比特位数。位的深度受其他因素的影响,主要是数字系统的动态范围。

声道(channel)一个分离的音轨。一个单声道的录音或者现场表演有一个声道,一个立体声道的录音或者现场表演有两个声道。一个多音轨的声道和表演可以有多个声道。在一个audio单元中,一个集合可以有一个或多个声道。

声道布局(audio layout):在一个录音音频中描述播放角色所处声道的信息。例如在立体声道中,声道1表示左前方,声道2表示右前方。

Chunk 含义:Chunk(组块)即由若干个字节(Byte)组成的数据块。Chunk有其特定的结构。结构:一个Chunk由chunk Header(块头)和Chunk Data(块数据)组成。若Chunk Data 没有数据,则此Chunk仅仅包含Chunk Header。由于我们是使用Chunk来存储数据到Chunk Data中的,因此实际使用中Chunk Data大小一般都不为零。组头含义(chunk header)组块数据的头部。代表数据块的格式。

裁切(clipping): 从一个受限的信号幅度到特定电平所损失的波形值。

明白AVFoundation

AVFoundation 基本函括了基本的音频操作,信息捕获、编辑基本信息与影片读写。这里只说简单的音频操作。

什么时候使用AVFoundation

1.获取媒体属性
2.自定义播放UI和行为
3.组成与组合媒体
4.重定义媒体信息
5.控制相机特性

AVFoundation位置

AVFoundation 位于核心层上层,在UIKit下层。 "工程目录结构"

AVFoundation类分组

AVFoundation类分组主要可以分成4部分:播放设置、信息捕获、编辑和读写4块。

播放(playback)

AVAsset

AVAsset是定时的视听媒体,它可以是视频、影片、歌曲、播客节目;可以是本地或者远程的;也可以是限定或者非限定的流;
获取一个AVAsset的方式有:程序捆绑;媒体库;图片库;获取网络地址;
AVAsset的组成:AVAssetTrackSegment->AVAssetTrack->AVAsset;
AVAssect信息获取会花费一定时间的原因:读取不同的文件格式、大文件文件信息读取,网络文件读取
异步键值加载协议:告诉我们媒体什么时候值有效,可以准备播放。

AVPlayer

AVPlayer是一个控制对象,它可以做的操作有:播放、停止和速率;不同AVAsset可以有不同的播放属性。

一个AVPlayer可以有多个AVAsset,OC通过AVPlayerItem来协调AVAsst和AVPlayer之间的关系。AVPlayerItem与AVAsset一样,同样有AVPlayerItemTrack对象。

AVPlayerLayer

播放对象与视图之间的实现需要通过AVPlayerLayer来控制。具体播放一个音频视频的步骤是:

播放步骤集合:

1.创建一个AVAsset
2.告诉asset的Track可以被加载了
3.一旦加载,为asset创建一个PlayerItem
4.把Item赋值给Player
5.把Player复制给PlayerLayer
6.等待直到Item准备好播放,然后开始播放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSArray *requestKeys = [NSArray arrayWithObjects:@“tracks,@”playable,nil];
[asset loadValuesAsynchoronouslyForKeys:requestKeys competionHandler:^{
  dispatch_async(dispatch_get_main_queue(),^{
      //complete block here
      NSError *err = nil;
      AVKeyValueStatus status =[asset statusOfValueForKey:@“tracks,error:&error];
      if(status == AVKeyValueStatusLoaded){
          self.PlayerItem = [AVPlayerItem playerItemWithAsset:asset];
          self.player = [AVPlayer playerWithPlayerItem:playerItem];
          [playerView  setPlayer:player];
      }else{
          //dont load ! need to do something~
      }
  });
}];
//等待加载完成
static void * playerItemStatueContext=&PlayerItemStatue;
//添加观察者
[playerItem addObserver:self forKeyPath:self options:0 context:playerItemStatueContext];

//显示到uiviewlayer层上
//添加结束通知
[[NSNotificationCenter defaultCenter]addObser:self selector:@selector(endMethod:) name:AVPlayerItemDidPlayEndTimeNotification];

添加滑动条:开始:暂停播放和移除通知。
更新播放时间:seekToTime:

关于播放要记住的:

1.Player 是一个控制器
2.player Item 控制当前状态
3.显示由一个player layer处理
4.注意你的播放队列。

编辑(Editing)

由asset集合组成小块作品:它可以是多个不同asset的组成;

AVCompositonTrackSegment->AVCompositionTrack->AVComposition

"工程目录结构" "工程目录结构"

时间控制需要注意的事项:

1.浮点数不允许精确的时间估算。
2.奇怪的时间尺度:29.97与30000/1001不相等。
3.混合的时间尺度:29.97fps视频和44.1kHz音频

OS中使用的时间: "工程目录结构" "工程目录结构" "工程目录结构"

音频混合:

1.临近的部分:AVCompostion;
2.合并音频轨迹:AVAudioMix;
3.合并视频轨迹:compositing;

音频混合对象:AVMutableAudioMixInputParameters –>AVMutableAudioMix
每一个音频混合输入参数:1.由一个音轨组成。2。描述了如何通过时间调整声音。
默认的声音不涉及混合。

视频复合:

1.临近的部分:AVComposition;
2.合并音频轨迹:AVAudioMix;
3.合并视频轨迹:AVVideoComposition;

AVComposition和AVVideoComposition "工程目录结构"

AVVideoComposition需要做的: 对于每一个时间范围的AVAsset:
1.创建一个对应时间范围的AVMutableVideoCompositionInstruction对象。
2.对于每一个轨迹,都是复合的一部分:为轨迹创建一个AVMutableVideoCompositionLayerInstruction对象。
3.明确指定透明度。明确指定开始与结束的矩阵转换。

音频VS视频
音频:1.对于每一个轨迹都是描述体积变化的时间范围。2.包含绝对的轨迹。
视频:1.对于每一个时间范围,在轨迹上描述指令组成信息。2.必须明确的包含轨迹

协调合并对象进行工作: AVAudioMix与AVVideoComposition:
1.他们都不是对象asset对象集合。
2.操作时使用对象Asset。
3.要使用行为时,将传递到控制对象。可以合并的控制对象有: "工程目录结构"

编辑要记住的:

1.composition是Asset的集合。他们由其他asset的segment对象组成。
2.他们通过轨迹进行音频混合。操作可能是不明显的。
3.视频Composition是一个合成的时间范围。它的操作要是显性的。

核心动画与媒体(Core animation and media)

1.所有的UIKit渲染都使用了核心动画。
2. 我们想对事物做的图形操作,如标题。
3.核心动画对于图形的渲染、投射和动画有极大的实用性。

核心动画与AV foundation
1. UIView使用CALayer 子类。
2. AVFoundation 提供CALayer子类:如,演示影片使用AVPlayerLayer。显示捕获的视频使用 AVCaptureVideoPreviewLayer。

单词记录

Audio Engineering Society 音频工程协会

differential pulse code modulation 差分脉冲编码调制

pulse-code modulation 脉码调制

adaptive delta pulse code modulation 自适应脉冲编码调制

noise floor 噪声层

quantization error
量化误差

amplitude resolution
幅度分辨率;幅值分辨率

in terms of 根据;用…的话; 就…而言; 以…为单位;

知识点收集(不定期更新)

mac OS下安装Yasm

  1. 到[yasm官网]ref2下载sourcecode。(我下的是yasm 1.2)
  2. 解压缩压缩包
  3. 终端terminate cd 到yasm1.2.0文件夹
  4. 执行./configure
  5. 执行make&&make install
  6. 待执行完成,输入yams —-version 查看ban版本。若存在,表示安装成功。

IOS CoreData error”Cannot create an NSPersistentStoreCoordinator with a nil model”

由于不小心删除了app中的数据模型文件,只能重新添加,之后给数据模型换名字、原名和修改path路径,怎么弄一直编译不通过。最后发现在build Phases》copy bundle Resources里没有模型的文件。添加上,编译通过。

IOS7 uiscrollview子视图下移

在NavigationController的视图下,给viewcontroller添加UISCrollview, scrollview添加子视图。发现scrollview中的子视图下移60px。 解决办法:见andy的博客

文件类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enum { DT_UNKNOWN = 0,  // unknown type           未知类型
    #define DT_UNKNOWN DT_UNKNOWN       
    DT_FIFO = 1,     // a named pipe, or FIFO  管道类型或先进先出
    #define DT_FIFO DT_FIFO
    DT_CHR = 2,     // a character device      字符设备、流
    #define DT_CHR DT_CHR
    DT_DIR = 4,     // a directory             目录文件
    #define DT_DIR DT_DIR
    DT_BLK = 6,     // a block device          块设备
    #define DT_BLK DT_BLK
    DT_REG = 8,     // regular file            普通常规文件
    #define DT_REG DT_REG
    DT_LNK = 10,    // symbolic link           符号链接
    #define DT_LNK DT_LNK
    DT_SOCK = 12,   // local domain socket     socket套接字
    #define DT_SOCK DT_SOCK                    
    DT_WHT = 14     // whiteout                
    #define DT_WHT DT_WHT  
};

Swift 函数与类

上一篇文章,初步了解了swift与xcode 6的内容。下面继续总结swift语法中的函数与类。

函数与闭包 (Functions and Closures)


swift函数定义规则是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
func 函数名(参数名:参数类型,参数名:参数类型,...)-> 返回值类型 {
    //函数主体
    return (a,b,c)
}
//例子
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()              // result:0
sumOf(42, 597, 12)   // result:651

/*----------- 返回一个函数名,它也是一个内嵌函数 ------------*/
func 函数名(参数名:参数类型,参数名:参数类型,...)-> (参数类型1 -> 返回类型1) {
    func nestedFunc(参数名:参数类型1)>返回类型1{
         return 返回类型1
    }
    return nestedFunc
}
//例子
func makeIncrementer() -> (Int -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)  //result: 8

/*----------- 把函数作为函数的一个参数 ------------*/
func 函数名(参数名:参数类型,函数名:参数类型 -> 返回类型) -> 返回类型{

}
//例子,判断是否存在小于10的数字
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
    for item in list {
        if condition(item) {
                return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)

* 返回类型支持返回多个值。方法是使用括号括住返回值:(rA,rB,rC)
* 参数列表也支持输入一组有效的参数值,将以数组形式传入函数。
* 内嵌函数函数可以互相嵌套,内部函数可以使用外部函数的值。
* 函数可以作为一个类型被返回。
* 函数可以作为一个参数被传入到另外一个函数。

闭包(Closure)

闭包是一个不显示参数与返回类型的特殊函数,你可以通过闭包来写一个匿名函数,将主体写在{}中,用in区分主体参数值返回类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    (参数名:参数类型)->返回类型 in
    //closure body
    return 返回类型值
}
// 例子,返回一个包含运行闭包后的结果集合。先看看map的定义:
//—————————————begin—————————————————
/// Return a Array containing the results of calling
/// `transform(x)` on each element `x` of `self`
/// 返回一组(每个子元素都)调用闭包后的结果集合
    func map<U>(transform: (T) -> U) -> U[]
//—————————————end—————————————————

var numbers = [20, 19, 7, 12]
var result  = numbers.map(
{
    (number: Int) -> Int in
    let result = 3 * number
    return result
})
println("\(result)")  // result: [60, 57, 21, 36]

var result = sort([1,5,3,12,2]){$0>$1}      //结果执行过程看下图
println("\(result)"); //result:[12,5,3,2,1]

"工程目录结构"

对象和类(Objects and Classes)

类的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class classname:inheritType{//:inheritType 是继承对象。在这里是可选值。
//here is your code
  //properties
      var aString : String
    {
////      注意不允许在set方法中对自身值进行赋值,否则将导致死循环。
//        set {//默认传入值用newValue表示,也可以用 set (newname) 来设置一个新值的别名
//            println("set value as \(newValue)") //println("set value as \(newname)")
//        }
//
//        get {
//            return self.aString
//        }

////   注意,set get必须同时存在,否则编译器报错。
////        willSetdidSet必须同时存在。
////        setgetwillSetdidSet不能同时存在
        willSet (anewvalue){ //这里使用了新值的别名anewvalue,默认为newValue
            println("self.aString:\(self.aString) set as newValue:\(anewvalue)");
        }
        didSet {
            println("after set \(self.aString)");
        }
    }
        // methodes
  init(){ //构造方法,若不添加编译器将会报错。
      super.init();//调用父类的构造方法。注意:这里必须顺序,先初始化父类构造方法,子类才能调用父类属性与方法。
      self.aString = aStr;
  }
  deinit{//析构方法,可选方法:此方法不需要参数

      }
/*
 override func aFuncInInheritType(){//父类方法重写.若需要重写父类方法,可以使用override关键字

  }

*
}

var aclass:MyClass = MyClass(aStr:"hello”);//此处willSet和didSet方法不执行。只执行了set和get方法
    aclass.aString = "hello,word;//此处执行willSetdidSet。说明willSetdidSet在初始化时不调用,setget方法每次对其进行赋值,都会被调用。

处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加?。如果?之前的 值是 nil,?后面的东西都会被忽略,并且整个表达式返回 nil。否则,?之后的东西都会被运行。

枚举与结构体(Enumerations and Structures)

枚举用enum来定义:enum 枚举名:枚举类型{枚举体},枚举类型可选。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//定义扑克的AK,数值从1开始增加,且定义一个simpleDescription函数,用于输出切换数值和名称。
enum Rank: Int { //若去掉:Int 则不允许赋值Ace = 1
        case Ace = 1
        case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King
        func simpleDescription() -> String {
            switch self {
            case Rank.Ace:
                return "ace"
            case Rank.Jack:
                return "jack"
            case .Queen:            //可用`.Queen`表示Rank.Queen
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.toRaw())
            }
        }
    }
let queen = Rank.Queen            //枚举一个ace
let queenRawValue = queen.toRaw()          //切换为数值,result:12
var des = queen.simpleDescription()      //输出枚举字符描述,result:ace
if let convertedRank = Rank.fromRaw(queenRawValue) { //12转换为枚举类型,等价于Rank.Queen
            let threeDescription = convertedRank.simpleDescription()
            println("\(threeDescription)")
        }

toRaw()转换为数值,fromRaw(avalue)将avalue转换为枚举型。

接口与扩展(Protocols and Extensions)

swift中同样用protocol来声明接口,类、枚举和结构体都可以实现接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}
class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}

mutating 用于修饰一个可被修改的函数体。当接口被类继承时,不需要用mutating 来重写方法体,当接口被枚举和结构体的使用,使用mutating关键字来重新修改结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
extension Int{
    func descript()->String{
        return "int value is:\(self)";
    }
}
extension Int: ExampleProtocol {
    var simpleDescription: String {
    return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}

使用extension为某个类型扩展变量或者方法。当运行时赋值对象与定义变量类型不符时,只实现变量类型的那部分实现。例如:

1
2
3
4
5
var simpleClassA: SimpleClass = SimpleClass();
simpleClassA.adjust();
let protocolValue: ExampleProtocol = simpleClassA;  //simpleClass类赋值给protocolValueprotocolValue为接口类型时,编译器只将SimpleClass实现ExampleProtocol 赋值给protocolValue,所以你不能通过protocolValue调用simpleclassA的属性或方法。
protocolValue.simpleDescription
// protocolValue.anotherProperty  // Uncomment to see the error

泛型(Generics)

在尖括号里写一个名字来创建一个泛型函数或者类型。泛型类型可以在函数和方法中使用,也可以在类,枚举和结构体使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//函数定义的乏型
func funcGenerics<T>(item:T) -> T[]{ //为方法定义泛型T,T的类型是参数的格式(由参数判定),返回是参数格式的数组
    var a = T[]();
    a += item;
    return a;
}
let fg = funcGenerics(hello);//返回一个String类型数组
let fg2= funcGenerics(3.141592628);//返回一个Double型数组。

//类泛型
class classGenerics<T> {
    func method(a:T){
        println(a);
    }
}
var gClass = classGenerics<String>();
    gClass.method("aString");
//或者-----Double类型
var gClass = classGenerics<Double>();
    gClass.method(3.1415926);

//枚举泛型
enum enumGenerics<T>{
        case a;
        case b(T);
        mutating func description(){
            switch self {
                case a:println( "result is none");
                case b(var val):println("result in b(T) is:\(val)”)//定义一个val变狼,类型为T
            }
        }
    }
var eg = enumGenerics<Int>.b(13);
    eg.description();
var eg = enumGenerics<String>.b("a string in enum Generics");
    eg.description();


//结构泛型
struct StructGenerics<T>{
     typealias ItemType = T //定义一个T类型别名。
     mutating func adjust(a: ItemType) {
 println(a);
     }
}
var sg = StructGenerics<Int>();
    sg.adjust(34);
var sg = StructGenerics<String>();
    sg.adjust("struct result is 34");

在类型名后面使用 where 来指定一个需求列表——例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类。

1
2
3
4
5
6
7
8
9
10
11
func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])

Switf 初学习

wwwdc 2014大会,苹果推出了新语言—雨燕swift。虽然很多开发者如往年一样,进行了大量的神吐槽,但是为了尽快成为坐在马背上的那个人—跟着趋势走,还是来赶快学习一下雨燕吧。

xcode 6 beta

伴随着雨燕发布的开发工具是xcode 6测试版,下载安装后。创建单个控制器的程序,我们可以知道可以选择Objective-c或者Swift语言来进行开发。不多说,选择Swift看看差异:

"工程目录结构"

  • 工程目录更简洁

    我们可以知道在xcode5的版本中,文件夹分为:工程文件夹、单元测试文件夹、框架文件夹和product文件夹。xcode6直接省去了框架文件夹。

  • 类文件的简化

    我们可以看到AppDelegate.swift和ViewController.swift两个类文件,main.storyboard一如往常。由此可知,类文件.h与.m合并为一个.swift,减少头文件与实现文件的切换过程。

  • 更少的支持文件

    没有了main.m程序入口文件、prefix.pch文件和国际化语言plist文件,仅仅剩下一个yourproject.plist配置文件。

  • 没有默认的lib文件

    通过.swiftimport UIKit和target>> build phase的link binary with lib 为空可知:foundation.frameworkUIKit.frameworkXCTest.framework三个基础框架系统不在显示,UIKit将作为必须框架自动为您导入到工程中.说明了:系统其实还是自动为您导入了一个UIKit框架,但以后link binary lib中将直接显示你导入和用到的framework&lib文件。

进入swift世界

Swift是建立在C与Objective-c优点上的用于编写IOS和Mac OSX应用的一门新语言。为了实现更简单、灵活而有趣的编程,它摒弃了C语言兼容上的限制性,集合了更多的安全编程模块和现代的编程特性。

再见hello world

按照编程界惯例,来写一条hello world。

1
println('hello world')

恭喜您,你学会了一门语言!lol,是不是很熟悉呢?其实就是C上的log语句,只不过少了分号。对的,swift允许您:

1. 不导入基础库。如i/o或者string文件。
2. 不需要main函数。在任何全局范围内写语句,都会被当作是入口。囧,当然这在工程里还是从appDelegate开始。
3. 不需要分号。blog主表示再次冒汗。

常量与变量

swift中对于简单型数据只有两个关键字,常量let和变量var。赋值时变量名=必须用空格分开,否则编译器报错。

1
2
3
4
5
6
7
8
9
10
11
/*------对于常量,你必须给他赋一个值-----------*/
let implicInt    = 70          //不明确的赋值
let implicDouble = 70.0        //不明确的赋值
let explicDouble:Double = 70   //明确说明是double类型赋值

/*------对于类型转换,必须明确指出-----------*/
let str        = "this is string"
let int_a  = 70
let int_b  = 80
let str_int    = str + String(int_a) //您必须明确指出需要转换类型,否则编译器会报错。
let string_ing = "\(int_a) + \(int_b) = \(int_a+int_b)" //另一种转换

可空变量既可以是一个值,也可以是一个nil来表明该值不存在。可空变量在变量名后用var 变量名:数据类型?表示。

数组与字典

通过[]来创建数组与字典,并且通过索引或者键值来创建元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*------创建空数组或字典-----------*/
let emptyarr = String[]()
let emptydic = Dictionary<string,float>()

/*------您也可以这样引用空数组-----------*/
     emptyarr = []
     emptydic = [:]

/*------创建带值的数组或字典-----------*/
var letters = ["A","B","C"]
    letters[1] = "A"
var letters = [
    "keyA":"A",
    "keyB":"B"
]

控制流

使用ifswitch作为控制条件,使用forfor-inwhiledo-while循环迭代。它们的参数是可选的,但是主体是必须的。

1
2
3
4
5
6
7
8
9
10
11
/*------迭代方式-----------*/
let arrs = [10,20,30,40]
var result = 0
for aVar in arrs {
result += aVar
}
println("result is:\(result)")

/*------if 条件语句必须是明确的布尔值-----------*/
var notAboolen = 0
if notAboolen {}     //这种方式是错的,switf 不知道notAboolen是布尔值。

你可以用let配合可空变量作为if的条件判断。在条件语句中可空变量赋值给let常量后,如果是nil则常量变为false布尔型;否则为true。

1
2
3
4
5
6
7
8
var optVar: String? = "John"  //result: hello,john
//optVar = nil                //result: hello!
var greeting = "Hello!"
let name = optVar
if name {                      //也可以这样写 if let name = optVar {}
    greeting = "Hello, \(name)"
}
println("\(greeting)")

swith 语句

switch语句支持所有类型的比较,不仅限与整型条件,也可以是复杂的判断操作等,无break语句。在swift中default条件是不能少的,并且最起码要有一条执行语句。而且执行完一个判断条件主体,程序直接跳出swith块。

1
2
3
4
5
6
7
8
9
10
11
12
13
var vResult = ""
let vegetable = "red pepper"
switch vegetable {
    case "celery":
        vResult = "Add some raisins and make ants on a log."
    case "cucumber", "watercress":
        vResult = "That would make a good tea sandwich."
    case let x where x.hasSuffix("pepper"): // x变量尾部是否包含pepper
        vResult = "Is it a spicy \(x)?"
    default:                                       //不可少
        vResult = "Everything tastes good in soup."//最起码包含一条语句
}
println("\(vResult)")     // result:Is it a spicy red pepper?

for-in 语句

for-in 对于枚举一个字典,我们可以使用两个用(键,值)来作为枚举方式的过程变量。对比OC来说,这不失为是一种更简洁的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var anEmployee = [
    "company":"myCompamy",
    "empName":"jonz",
    "department":"dev",
    "salary":"3000"
]
println("here is an employee infomation:")
for (key,value) in anEmployee
{
    println("       \(key):\(value)")
}
/*-------the result is:--------------*/
here is an employee infomation:
    empName:jonz
    department:dev
    salary:3000
    company:myCompamy

使用.....来表示范围

对于明确循环界限的迭代,我们可以使用..来作循环。比如求从0到3之间的数字和:

1
2
3
4
5
6
7
8
9
10
11
var count = 0
for i in 0..4{ //注意迭代编程中的少1问题,这里相当于for var i=0;i<4;i++
    count += i
}
println("\(count)") //result is:6

count = 0
for i in 0...3{ //注意迭代编程中的少1问题,这里相当于for var i=0;i<=3;i++
    count += i
}
println("\(count)") //result is: 6

我们知道,新的特性使语句更加简短,..不包含范围的上界,...包含了范围的上界.

end line

好了,就先写到这里。对于编程里的函数与类、对象,由于内容比较多将记录在下一篇blog里。

Octopress 搭建记录

花了大半天的时间研究了octopress的搭建,不会命令行的悲剧。虽然网上有许多教程,但是自己做了一遍,才发现也没有那么简单。菜鸟一思考,上帝和神人就发笑。:)

基本搭建

具体的搭建,在这里就不一一详细描述,网上一抓一大把。大家可以参考一下大神们的一些博客:

在这里简单描述一下步骤:

1.安装git环境,mac上自带git。若其他环境,请google之。
2.安装rbenv或者RVM
3.使用git从github上下载octopress安装文件,并且用终端安装

1
2
3
4
5
6
7
8
9
#-------------下载过程------------------------ 
git clone git://github.com/imathis/octopress.git octopress  //github上下载,等待下载完成
cd  octopress                                               //移动到octopress文件夹  
#-------------安装过程------------------------  
gem    install bundler 
rbenv  rehash    # If you use rbenv, rehash to be able to run the bundle command
bundle install
#-------------安装默认主题------------------------ 
rake install

以上步骤操作完后,输入rake preview,然后在safari上输入localhost:4000或者127.0.0.01:4000(推荐),预览的blog主题效果。在这里,自己遇到了safari显示为空。原因是在safari7和mac os 10.9上有bug,提供的解决办法见链接。

1
2
3
4
5
#-------------预览主题------------------------
rake preview                        //输入后,通过safari url: 127.0.0.01:4000上预览
#-------------解决预览空白方法------------------------
# $ echo gem \"thin\" >> Gemfile
# $ bundle install

4.github上创建一个博客地址。以自己的账号(用户名:dev-Zhuang)为例子,说一下步骤:
创建github账号后,点New repository创建一个新的repository,命名(必须)为:dev-Zhuang.github.com即可。
这里不需要到settings中勾选automatic page generate,保持代码库为空,然后将你本地的博客上传到代码库即可。自己在这一步参考了网上的资料,走了不少弯路,导致了上传过程中git不断的报错,T_T。

5.配置博客,然后上传到github上。
这里以后每次写完blog,都要用rake generate和rake deploy上传。配置博客过程就不在细说,自行参考相关文献。

1
2
3
4
5
6
-------------设置上传地址------------------------
rake setup_github_pages
-------------在要求输入的地址处输入,然后输入账号密码----------
https://github.com/dev-Zhuang/dev-Zhuang.github.com.git
rake generate       //重新生成
rake deploy        //上传

6. 搭建分享平台与评论系统。
这一步见唐巧boy中的内容。微博平台拷贝一下代码,修改一下显示参数即可。评论系统用的是友言的,注册拷贝代码.因为改系统是根据uid和文章index来做评论依据,大家需要先注册自己的账号获取uid。so easy!

好了,就写到这里。学习markdown语法,写自己的博客去吧,have fun!