GVKun编程网logo

swift开发笔记8 - sqlite3数据的使用(xcode 7,ios9)

14

本文将分享swift开发笔记8-sqlite3数据的使用(xcode7,ios9)的详细内容,此外,我们还将为大家带来关于#小贼音乐--Swift开发笔记Step1、#小贼音乐--Swift开发笔记S

本文将分享swift开发笔记8 - sqlite3数据的使用(xcode 7,ios9)的详细内容,此外,我们还将为大家带来关于# 小贼音乐--Swift开发笔记 Step 1、#小贼音乐--Swift开发笔记 Step 2、3、swift开发iOS——swift数据类型、ios sqlite3数据库操作的相关知识,希望对你有所帮助。

本文目录一览:

swift开发笔记8 - sqlite3数据的使用(xcode 7,ios9)

swift开发笔记8 - sqlite3数据的使用(xcode 7,ios9)

由于考虑将来还要开发Android版本app,为了移植方便,所以使用了sqlite3来做数据持久化,到时候把sql语句拷过去还能用大笑

1、 首先用xcode载入sqlite3类库

选择工程的TARGETS-build phases-link binary with libraries,点击“+”按钮,选择类库,点击“add”添加:

 

(输入sql查找:)

 

2、 sqlite3是 c语言写的类库,所以还要引用他的头文件。在工程里新建一个文件,类型为“.h”文件,命名为:ProjectSecretary2-Bridging-Header.h ,这个文件就是桥接文件,然后在这个文件里加一行代码:

 

#import "sqlite3.h"

 

3、 然后告诉xcode编译时要引入这个类库头文件

      在targets->build settings ->Object-C Bridging Header 输入头文件名即可,要注意的是

 

  • 找swift compiler时,要选择“ALL”和“Combined”,否则不好找。
  • 输入文件名时可能要加上级文件路径,自己试试好了吐舌头

 

 

4、 现在可以在代码里打开数据库了:

 

[objc] view plain copy

  1. let DBFILE_NAME = "psList.sqlite3"  
  2. var db:COpaquePointer = nil  
  3. //获取sqlite3数据库文件位置  
  4. func applicationDocumentsDirectoryFile() ->String {  
  5.     let  documentDirectory: NSArray = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)  
  6.     let path = documentDirectory[0].stringByAppendingPathComponent(DBFILE_NAME) as String  
  7.     NSLog("path : %@", path)  
  8.     return path  
  9. }  
  10.   
  11. //创建一个系统配置表  
  12. func getSysConfig()->Dictionary<String,String>{  
  13.     var theResult:Dictionary<String,String>=Dictionary<String,String>()  
  14.     let writableDBPath = self.applicationDocumentsDirectoryFile()  
  15.     let cpath = writableDBPath.cStringUsingEncoding(NSUTF8StringEncoding)  
  16.       
  17.     if sqlite3_open(cpath!, &db) != SQLITE_OK {  
  18.         sqlite3_close(db)  
  19.         assert(false, "数据库打开失败。")  
  20.     } else {  
  21.         //创建一个系统参数配置表,有3个字段,分别是 名字、值和备注  
  22.         let sql = "CREATE TABLE IF NOT EXISTS  SysConfig (name TEXT PRIMARY KEY, value TEXT , comment TEXT)"  
  23.         let cSql = sql.cStringUsingEncoding(NSUTF8StringEncoding)  
  24.           
  25.         if (sqlite3_exec(db,cSql!, nil, nil, nil) != SQLITE_OK) {  
  26.             sqlite3_close(db)  
  27.             assert(false, "建表失败。")  
  28.         }  
  29.         sqlite3_close(db)  
  30.     }  
  31.   
  32.     return theResult  
  33. }  

# 小贼音乐--Swift开发笔记 Step 1

# 小贼音乐--Swift开发笔记 Step 1


小贼音乐的最终效果如下:


本篇博文希望达到的效果如下:


开头先说说别的

先说说,为什么要开发这个吧。因为在前段时间,看到了一个很有趣的APP---emo。是emotion的简写。没有下载的朋友,可以尝试下载一下。emo的特点就是,使用表情识别,推断当前用户的心情,进而给用户推送音乐。用了几次,觉得推送的音乐挺不错的。


创建swift项目

创建一个swift项目,这个就不详述了,项目名称可以自定义,不过下面的过程,假定项目名称为ZHEmotionMusic。在开始项目前,可以给Xcode添加一个插件,VVDocumenter-Xcode,功能为给方法添加注释,从现在起多写写注释,不仅仅是方便他人的阅读,也是方便自己以后的回顾。


接入一登SDK

首先了解一登,开发的APP有一个过程,是人脸识别。而一登,看官网主要上的描述,主要侧重点在刷脸登陆,但其SDK依旧提供人脸表情识别的功能。(但有一个坑,大家后面也会发现,一登如果要识别人脸表情,需要高级功能,要申请高级功能还得和一登工作人员商量。没办法,一开始没仔细看,不过其实大致的接口是类似。再说一下,国内的face++的识别效果,应该会比一登好,但是一登会比较适合这个音乐app,毕竟emo也是用一登)

因为不能直接获得人脸的表情状态,但毕竟是为了学习,可以变通一下,一登的基本权限,可以获得人脸的微笑程度,现在我们把众多的表情,分成两个。1)开心 2)不开心。(就当随意练手吧,不要在意这些)

现在我们集成SDK,分为几个步骤。

  1. 在官网首页点击【注册】完成一登开发者注册。

  2. 在一登开发者中心,创建一个新应用。应用名称可以直接填项目名称,应用类型为影音图像;下载地址和Apple ID可以忽略。注意bundle得和XCode中项目的Bundle Identifier一致。如下图:

创建好应用后,注意应用中基本信息中含有APP ID 和 APP Secret,在开发过程中会使用。

  1. 到一登SDK的Github上,下载SDK,可以clone,也可以直接下载zip文件。

  2. 在一登 GitHub 下载一登 iOS SDK。将 SDK 包中的文件添加至本地工程,其中包括:SuperIDSDKSettings.bundle、 libSuperIDSDK.a、SIDFaceFeatureViewController.h、SuperID.h,SuperIDDelegate.h 共5个文件。为了更好的管理文档,注意记得把这五个文档归为一个Group中。

  1. 在工程引入静态库之后"需要在编译时添加 -ObjC 和 -lstdc++ 编译选项。方法:xcodeproj->Build Settings->Linking->Other Linker Flags,在 Other Linker Flags 选项中,双击该选项,点击弹出框左下角的 + 按钮,分别添加 “-ObjC” 字符和 “-lstdc++” 字符(如下图)。

  1. 添加依赖库,

如果你的应用无法正常通过编译,请添加SDK所需的依赖库。主要为:

  • CoreTelephony.framework

  • CoreMedia.framework

  • AVFoundation.framework

  • libc++.dylib

添加路径为:工程->Build Phases->Link Binary With Libraries->Add->选择上述的依赖库。


SDK初始化

注意,我们的项目使用的是Swift语言,但是一登SDK是用objective-c编写的。你可能会焦急,这个怎么办? 不用担心,Apple公司允许开发人员,在Swift中调用objective-c,需要进行桥接。怎么做呢?看下面的步骤。

按command+n 创建一个新文件,选择IOS-->Source-->Cocoa Touch Class,随意输入类名,例如OC
Object,注意选择语言为objective-c。当你在Swift项目中创建一个object-c文件时候,XCode会自动提示你,创建 项目名称-Bridging-Header.h 文件(这里是 ZHEmotionMusic-Bridging-Header.h),这个文件起桥接作用,你可以在上面引入你需要调用的objective-c头文件,方式和普通的objective-c引入头文件类似,例如,在项目中会使用到 SuperID.h 。所以在里面添加:

    #import "SuperID.h"

声明完后,就可以在项目中使用一登SDK了,不过注意的是,在项目中,我们是使用Swift代码进行编写,即使调用objective-c的类,也是使用Swift方式调用,XCode会帮你转换,这个不用我们担心。

填写一登APPID和APPSecret

在SDK文档中有介绍,调用的借口为

- (void)registerAppWithAppID:(NSString *)appID withAppSecret:(NSString *)appSecret;

具体的代码为:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

        [[SuperID sharedInstance]registerAppWithAppID:@"应用的AppID" withAppSecret:@"应用的AppSecret"];

        return YES;
    }

在我们的项目中,使用Swift编写代码如下:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Override point for customization after application launch.


            //在代码中向一登 SDK 注册你的 AppID 和 AppSecret
            SuperID.sharedInstance().registerAppWithAppID("LDYEYQoR6lnpA2mehpZVzvzK", withAppSecret: "sETEcYSE1g5OYnmLwSybGheY")

            //设置SDK语言模式为简体中文
            SuperID.setLanguageMode(SIDLanguageMode.SimplifiedChineseMode)

            //设置SDK调试模式,应用发布时,注意需要关闭
            SuperID.setDebugMode(true);

            return true
        }

至此,一登SDK接入完毕,下面看如何调用其人脸识别的功能。


调用一登SDK获得人脸属性。

在您调用 SIDEmotionViewController(具有人脸识别的View Controller) 的当前 View Controller 中,您需要设置当前 View Controller 作为 SDK 的协议委托对象,并在当前 VC 中声明继承一登 SDK 的Protocol(SuperIDDelegate)并声明 SDK 单例对象,具体代码如下所示。

    //先让当前ViewController 实现 SuperIDDelegate 协议
    class ViewController: UIViewController , SuperIDDelegate 

然后重载viewWillAppear方法。

     /**
        Description
            View将出现时,所做的操作,这里添加了SDK的委托声明
        :param: animated
        */
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)

            superIdSdk = SuperID.sharedInstance() // 获取SDK单例
            superIdSdk?.delegate = self //设置委托对象
        }

然后,在storyboard中,首先选中当前的ViewController,然后在Utilities中的Attributes Inspector中,调整size为iphone4-inch(个人喜好,不喜欢方形的),然后,添加一个button,放在当前View Controller 中间,然后选中button,按control键,连接button至ViewController中,选择Connection为Action,命名为getFaceFeature。现在的目的是,测试一登的SDK,我们希望,点击button,能够调用用于完成人脸属性检测的ViewController,代码如下:

    @IBAction fun getFaceFeature(sender: AnyObject) {
            //getAuthorityOfCamera()

            var error : NSError? = nil;

            var SIDEmotionViewController  = superIdSdk!.obtainFaceFeatureViewControllerWithError(&error) as? UIViewController;

            if let SEV = SIDEmotionViewController{
                //采用present的方式弹出人脸情绪的功能:
                self.presentViewController(SIDEmotionViewController!, animated: true, completion: nil)

            }
            else{
                println("\(error?.code)     \(error?.description)")
            }

        }

按Command+B,若无错误,则说明上面的步骤正确。可能会有一些警告信息,可以忽略。

可以进行测试,注意,因为表情识别会用到,摄像头,可是IOS simulator不支持,所以,需要使用真机进行测试,这需要苹果开发者账号,如果没有,可以选在在淘宝上搜 “Xcode 真机测试”,可以允许你在mac上对一台iphone进行真机测试,具体怎么做,可以淘宝搜,店主会详细告诉你。

如果,你一切顺利,当点击按钮,会提示你,没有权限,下面我们需要写一段代码,让用户每次点击按钮,如果用户没有获得摄像头的权限,可以选择赋予摄像头权限,代码的逻辑很简单,就是先检查当前的权限的状态,然后根据状态进行判断。代码如下:

 /**
    Description 
            调用该方法,获取调用相机权限
    */
    func getAuthorityOfCamera(){
        var status:AVAuthorizationStatus =  AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)


        if(status == AVAuthorizationStatus.Authorized) { // authorized
            return;
        }
        else {

            AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: {
                (Bool granted) -> Void in

                //如果用户赋予了权限
                if(granted){

                }
                //如果没有赋予权限
                else{

                }
            })
        }
    }

然后,注意将getFaceFeature中的一个注释去掉。

 getAuthorityOfCamera()  // 去掉注释。

然后编译运行试试,会出现一个新的界面,界面使用了前置摄像头,你只需将脸对着前置摄像头,从而进行识别。

你会奇怪,识别完后,似乎什么事情都没有发生,这是因为,你并没有设定,识别完后做什么。其实。当一登用户在一登 SDK 完成人脸属性检测事件后,SDK 将执行协议中的相应方法,开发者可在对应的方法中进行根据需要相应事件处理。方法是superID,我们需要实现它。代码如下:

     /**
        Description
                用户在一登 SDK 完成人脸属性检测事件后,SDK 将执行协议中的方法,就是本方法,开发者可本方法中进行根据需要相应事件处理
        :param: sender       SuperID实例
        :param: featureInfo  检测的人脸信息
        :param: error        error == nil 则不发生错误; 否则发生错误。
        */
        func superID(sender: SuperID!, userDidFinishGetFaceFeatureWithFeatureInfo featureInfo: [NSObject : AnyObject]!, error: NSError!) {
            if(error == nil){
                println("操作成功!")

                println(featureInfo)

            }
            else{
                println("操作失败!")

                println("\(error.code)   \(error.description)")
            }
        }

当你再次运行,你会在All out中,发现,输出了一些内容。例如:

    操作成功!
    [eyeglasses: {
        result = 1;
        score = "0.992422";
    }, male: {
        result = 1;
        score = "0.999256";
    }, sunglasses: {
        result = 0;
        score = "0.393262";
    }, smiling: {
        result = 0;
        score = "0.001676";
    }, age: 25.96, resource_id: 55620c94de77d8ae668e1fc4, mustache: {
        result = 1;
        score = "0.518885";
    }]

好了,一登SDK暂且OK。下面让我们美化一下。


简单美化下

    顺便提一句,app_icon ,是用Sketch来设计制作的,请大家体谅一下,不是Sketch不好用,而是本人捉急的艺术功底。

先看 app_icon.png,这个拖至Images.xcassets的AppIcon中。

再添加几个图片,

basic.png

happy.png

sad.png

这些是后面步骤会使用到的图片。现在AppIcon已经有图片了,所以当你再次运行时,iphone手机上的图标就有了。现在我们改改图标下面显示的App名字。也很简单,就是打开Supporting Files-->Info.plist文件,找到,Bundle name,修改为-->小贼音乐。如图所示:

打开Main.storyboard,删除原来的button,现在选择一个image View放到上面,设置大小为250*250,设置图片为basic, 再添加两个label,最后,如图所示:

上面的image view 和两个label都使用了auto layout布局,这个大家可以去了解一下,然后选择合适的方式将它们展示出来就可以了。

注意需要设定中间ImageView的layer.cornerRadius,不少人喜欢在代码中实现,但本人懒,不太喜欢用代码。但是,有无法直接在ImageView的属性中进行设定,推荐大家一种方式,使用User Defined Runtime Attributes,详情可看这里。最终,如下图:

按control,将image view和两个label都绑定到View Controller中。

  ///ImageView实例
    @IBOutlet weak var imageView: UIImageView!

    ///第一个Label标签
    @IBOutlet weak var label1: UILabel!

    /// 第二个Label标签
    @IBOutlet weak var label2: UILabel!

在Main.storyboard中,给当前的view Controller 添加一个Long Press Gesture Recognizer,因为设定是长按屏幕,进行扫描人脸。如果不了解 Gesture recognizer,可以去了解一下,简单的说,就是手势识别,这个Long Press Gesture Recognizer是专门用来识别长按屏幕这个手势操作的,是苹果官方提供的手势识别,当然你也可以自己写自己的手势,不过我们暂时使用这个手势就足够了。

按control将手势连接至ViewController,选择Action,命名位longPressAction,大致内容和上面的getFaceFeature一样。

     /**
        Description
            处理用户长按屏幕的行动

        :param: sender
        */
        @IBAction func longPressAction(sender: AnyObject) {
            getAuthorityOfCamera()

            var error : NSError? = nil;

            var SIDEmotionViewController  = superIdSdk!.obtainFaceFeatureViewControllerWithError(&error) as? UIViewController;

            if let SEV = SIDEmotionViewController{
                //采用present的方式弹出人脸情绪的功能:
                self.presentViewController(SIDEmotionViewController!, animated: true, completion: nil)

            }
            else{
                println("\(error?.code)     \(error?.description)")
            }

        }

但我们更新一下,实现的协议方法superID,

 /**
    Description
            用户在一登 SDK 完成人脸属性检测事件后,SDK 将执行协议中的方法,就是本方法,开发者可本方法中进行根据需要相应事件处理
    :param: sender       SuperID实例
    :param: featureInfo  检测的人脸信息
    :param: error        error == nil 则不发生错误; 否则发生错误。
    */
    func superID(sender: SuperID!, userDidFinishGetFaceFeatureWithFeatureInfo featureInfo: [NSObject : AnyObject]!, error: NSError!) {
        if(error == nil){
            println("操作成功!")

            println(featureInfo)
//            var info = featureInfo!

            //因为featureInfo和其内部的数据,都是optional类型,需要 unwrap
            if let info = featureInfo {
                var smileResult = info["smiling"]!
                var result = smileResult["result"] as! Int
                var score = smileResult["score"] as! Double
                println(score)
                if result == 1 {
                    imageView.image = UIImage(named: "happy")
                    label1.text = "诶哟!"
                    label2.text = "今天心情不错哦!"
                }else{
                    imageView.image = UIImage(named: "sad")
                    label1.text = "唉!一言以蔽之"
                    label2.text = "心好涩"
                }
            }

        }
        else{
            println("操作失败!")

            println("\(error.code)   \(error.description)")
        }
    }

最后一个步骤,让我们修改一下Launch image,查看 项目--> General --> App Icons and Launch Images --> Launch screen file。 默认的Launch image是LaunchScreen.xib,这个在项目创建时自动生成的,在这里,我们选择Main.storyboard作为Launch image。

可以尝试运行,测试一下结果如何。第一步,暂时到此结束。


笔者注:欢迎非商业转载,但请一定注明出处

如果你认为这篇不错,也有闲钱,那你可以用支付宝随便捐助一快两块的,以慰劳笔者的辛苦:

#小贼音乐--Swift开发笔记 Step 2

#小贼音乐--Swift开发笔记 Step 2

小贼音乐的最终效果如下:


在step1中,我们可以识别人脸表情,在这一步中,我们加入音乐的功能。时不我待,开始吧。

首先了解我们希望得到的最终结果,如下图,是一个能够扫描心情,并且播放音乐:


导入CircularProgressView

什么是ProgressView,应该了解,那么前面加了个Circular,意思很明确了,就是在圆形的progress view了,不过它的实现并没有继承progress view,而是继承自view再实现。它虽然带着ProgressView的名字,却也扮演着播放器的角色。可以看这篇blog了解它。由于原作者的版本,音乐播放并不支持网络上的音乐,所以,我更新了其实现方式,更改了内部的播放器,让它支持网络上的音乐文件。更新的CircularProgressView开源在github。 喜欢点个赞哈

按照github上面的步骤,我们将CircularProgressView.h和CircularProgressView.m导入我们的项目中,并且新建了一个group,起名CircularProgressView。方便代码审阅。并且把CircularProgressViewDemo中的“我的歌声里”这首歌添加进我们的项目。

导入了objective-c代码,由于我们在项目中需要使用它,所以需要在ZHEmotionMusic-Bridging-Header中登记一下,添加代码如下:

    #import "CircularProgressView.h"

然后在Main.storyboard中,添加一个View(注意,放在原先图像后面),在其对应的Identity Inspector中,更改class为CircularProgressView.h。在size inspector中,更改大小为256*256。
因为我们希望一会儿圆圈的line width是4.然后,往ViewController中,添加如下代码。

    self.circularProgressView.backColor = UIColor(red: 236.0 / 255.0, green: 236.0 / 255.0, blue: 236.0/255.0, alpha: 1.0)
            self.circularProgressView.progressColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1.0)
            self.circularProgressView.lineWidth = 4
            self.circularProgressView.audioURL = NSBundle.mainBundle().URLForResource("我的歌声里", withExtension: "mp3")
             self.circularProgressView.play()

然后尝试运行,啊哦,我们希望的圈圈和原来的视图中间的图像不是很搭,这下怎么办?原因是,师徒中间的imageview使用了autolayout进行了适配,所以,为了让它们时间永远保存某种关系,可以对后面添加的view进行autolayout,我选择的方式,就是让view的top,bottom,left,right始终和imageView保持距离3。增加完autolayout后,运行,结果如下:

中间的黑色线条,其在园中的百分比,就是歌曲进行的百分比。同时你可以听到音乐的播放。


水水的添加音乐

由于暂时没有找到合适的根据心情,提供音乐的API,所以,就先水水的拿一个冒牌的东东来暂时替代一下吧。一些内容来自【老镇出品】实战-豆瓣电台,如果从没使用swift进行网络编程的话,可以去看一下这个视频教程,里面的内容相对来说更基础,在我们的实现中,对视频中讲解的代码做了一些改进,如果你看了视频的话,可以稍微注意下,希望有所帮助。

在step1中,我们暂且定义了两个表情,开心,不开心。所以需要两个源,一个是获取开心的音乐,一个获取不开心的音乐,之所以说水水的,看下面的代码:

/// 快乐就听摇滚
let happySongsURL = "http://douban.fm/j/mine/playlist?channel=7"

/// 悲伤就听R&B
let sadSongsURL = "http://douban.fm/j/mine/playlist?channel=14"

从代码中,可以体会出,我将豆瓣的摇滚当做快乐的音乐源,将R&B当做悲伤的音乐源。不好意思,暂时没有合适的,就先这样了,大家见谅一下吧。

下一步,新建一个HttpController.swift文件,然后添加如下代码:

import UIKit

/**
*  协议负责处理网络连接后的数据处理
*/
protocol HttpProtocol{
    /**
    负责处理网络连接后的数据处理

    :param: results 需要处理的数据
    */
    func didReceiveResults(results : NSDictionary)

}

/**
*  负责网络连接
*/
class HttpController: NSObject {

    var delegate : HttpProtocol?

    /**
        给定url,访问网络资源

    :param: url 资源URL地址
    */
    func onSearch(url : String) {

        UIApplication.sharedApplication().networkActivityIndicatorVisible = true

        let nsUrl = NSURL(string: url)
        let request:NSURLRequest = NSURLRequest(URL : nsUrl!)
        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: config)
        let task = session.dataTaskWithRequest(request){
            (data,response,error) -> Void in
            if error == nil {

                var jsonResult : NSDictionary  = NSJSONSerialization.JSONObjectWithData(data,options:NSJSONReadingOptions.MutableContainers, error : nil) as! NSDictionary


                self.delegate?.didReceiveResults(jsonResult)

            }else{
                println(error)
            }


        }

        task.resume()

    }


}

HttpController的作用是负责Http的连接,通过IOS的NSURLSession,获取我们需要的内容。

何时调用HttpController呢? 答案就是,扫描表情之后,所以需要修改ViewController。首先,在ViewController中,添加一个属性,

/// 用来获取网络数据
var http : HttpController = HttpController()

http是HttpController的一个实例,用来获取网络的数据。修改SuperID方法,如下:

 /**
    Description
            用户在一登 SDK 完成人脸属性检测事件后,SDK 将执行协议中的方法,就是本方法,开发者可本方法中进行根据需要相应事件处理
    :param: sender       SuperID实例
    :param: featureInfo  检测的人脸信息
    :param: error        error == nil 则不发生错误; 否则发生错误。
    */
    func superID(sender: SuperID!, userDidFinishGetFaceFeatureWithFeatureInfo featureInfo: [NSObject : AnyObject]!, error: NSError!) {
        if(error == nil){
            println("操作成功!")

            println(featureInfo)
//            var info = featureInfo!

            //因为featureInfo和其内部的数据,都是optional类型,需要 unwrap
            if let info = featureInfo {
                var smileResult = info["smiling"]!
                var result = smileResult["result"] as! Int
                var score = smileResult["score"] as! Double
                println(score)
                if result == 1 {
                    imageView.image = UIImage(named: "happy")
                    label1.text = "诶哟!"
                    label2.text = "今天心情不错哦!"
                    //获取happy歌曲的数据
                    http.onSearch(happySongsURL)

                }else{
                    imageView.image = UIImage(named: "sad")
                    label1.text = "唉!一言以蔽之"
                    label2.text = "心好涩"
                    //获取sad歌曲的数据
                    http.onSearch(sadSongsURL)
                }
            }

        }
        else{
            println("操作失败!")

            println("\(error.code)   \(error.description)")
        }
    }

从前面可以看到,HttpController有一个delegate,属于HttpProtocol类型,专门负责处理从网络上获取的得来的数据。所以,我们让ViewController视线HttpProtocol协议,然后在其内部实现didReceiveResults方法,如下:

    /**
        负责处理从网络上获取的数据

    :param: results 获取得到的数据
    */
    func didReceiveResults(results : NSDictionary){
        println("数据成功接收")
        println(results)
    }

不要忘了在viewDidLoad中,设置http的delegate,添加如下代码:

//http的处理交给当前实现HttpProtocol的ViewController来处理
        http.delegate = self

运行,控制台会输出,一些从网络上获取得到的歌曲信息。现在来看看怎么处理这些信息。前提是,了解这些信息的格式,这些信息都是json数据格式,在浏览器中,访问 http://douban.fm/j/mine/playlist?channel=7 。 显示一大堆数据,它们都是json格式,复制这些数据,然后访问 http://jsoneditoronline.org 。json editor online 能够将乱乱的json格式数据,排列成有序的,易于阅读的格式。看一下获取的json数据参考格式:

    {
        "r": 0,
        "is_show_quick_start": 0,
        "song": [
            {
                "album": "/subject/7153475/",
                "picture": "http://img3.douban.com/lpic/s7022222.jpg",
                "ssid": "cd19",
                "artist": "Herman''s Hermits",
                "url": "http://mr3.douban.com/201406201304/a687b5d793bb3233e243f05a3e502b20/view/song/small/p2087018.mp3",
                "company": "Warner",
                "title": "Smile Please",
                "rating_avg": 0,
                "length": 165,
                "subtype": "",
                "public_time": "2004",
                "songlists_count": 0,
                "sid": "2087018",
                "aid": "7153475",
                "sha256": "5f6ba79e1463c1b54d0be17d090d4ee09d55121a91905ddd2217b0ba458ca7a2",
                "kbps": "64",
                "albumtitle": "The Best of",
                "like": "0"
            },
            {
                "album": "/subject/1947603/",
                "picture": "http://img3.douban.com/lpic/s4458282.jpg",
                "ssid": "b80e",
                "artist": "Pompeii",
                "url": "http://mr3.douban.com/201406201304/f8ea9c7ba0793030c8c486152d51527e/view/song/small/p2087210.mp3",
                "company": "Warner",
                "title": "Ten Hundred Lights",
                "rating_avg": 3.81894,
                "length": 255,
                "subtype": "",
                "public_time": "2006",
                "songlists_count": 0,
                "sid": "2087210",
                "aid": "1947603",
                "sha256": "761fb793fd0571663c469a10bf9fc3bf0e2e3b329ecc5dddad8a2d28fd7ac0c7",
                "kbps": "64",
                "albumtitle": "Assembly",
                "like": "0"
            }
        ]
    } 

了解了格式,就能够依据格式,提取出我们需要的信息。在ViewController中,添加:

/// 歌曲列表
    var songs = NSArray()

songs用来,保存歌曲。

更新didReceiveResults方法,

// MARK: - HttpProtocol Method
    /**
        负责处理从网络上获取的数据

    :param: results 获取得到的数据
    */
    func didReceiveResults(results : NSDictionary){
        println("数据成功接收")
//        println(results)
        self.songs = results["song"] as! NSArray

        let song0 = self.songs[0] as! NSDictionary

        let songURL = song0["url"] as! String
        println("song URL: \(songURL)")

        //更新界面UI的操作,放在主线程,提高反应速度
        dispatch_async(dispatch_get_main_queue(), {
            () ->Void in
            self.circularProgressView.stop()
            self.circularProgressView.audioURL = NSURL(string: songURL)
            self.circularProgressView.play()

            let imageUrl = song0["picture"] as! String
            self.onSetImage(imageUrl)
            UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        })

    }

onSetImage方法的代码如下:

/**
        处理图片,调用ImageLoader单例进行图片缓存。

    :param: url
    */
    func onSetImage(url : String){

        ImageLoader.sharedLoader.imageForUrl(url, completionHandler:{(image: UIImage?, url: String) in
            self.imageView.image = image
        })

    }

ImageLoader实现图片缓存,采用单例模式,下面看其实现代码:

//
//  ImageLoader.swift
//  ZHEmotionMusic
//
//  Created by 钟桓 on 15/5/26.
//  Copyright (c) 2015年 ZH. All rights reserved.
//


import UIKit

class ImageLoader {

    var cache = NSCache()

    class var sharedLoader : ImageLoader {
        struct Static {
            static let instance : ImageLoader = ImageLoader()
        }
        return Static.instance
    }

    func imageForUrl(urlString: String, completionHandler:(image: UIImage?, url: String) -> ()) {


        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in
            var data: NSData? = self.cache.objectForKey(urlString) as? NSData

            if let goodData = data {
                let image = UIImage(data: goodData)
                dispatch_async(dispatch_get_main_queue(), {() in
                    completionHandler(image: image, url: urlString)
                })
                return
            }

            var downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: {(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
                if (error != nil) {
                    completionHandler(image: nil, url: urlString)
                    return
                }

                if data != nil {
                    let image = UIImage(data: data)
                    self.cache.setObject(data, forKey: urlString)
                    dispatch_async(dispatch_get_main_queue(), {() in
                        completionHandler(image: image, url: urlString)
                    })
                    return
                }

            })
            downloadTask.resume()
        })

    }
}

现在运行程序,每次扫描人脸后,都会有新的歌曲进行播放。但你会发现,每当一首歌曲播放完毕,程序停滞,没有行动。因为我们没有对歌曲播放完后改采取的行动进行编写。在ViewController中添加下面三个方法:

// MARK: - CircularProgressViewDelegate Method

//    - (void)updateProgressViewWithPlayer:(AVAudioPlayer *)player;
//    - (void)updatePlayOrPauseButton;
//    - (void)playerDidFinishPlaying;

    /**
        歌曲暂停时调用
    */
    func updatePlayOrPauseButton() {

    }

    /**
        可以使用该方法,通过player的信息,对view进行更新。

    :param: player 播放器
    */
    func updateProgressViewWithPlayer(player: MPMoviePlayerController!) {

    }

    /**
        每当播放结束时调用
    */
    func playerDidFinishPlaying() {

    }

聪明的你,注意到了MARK标志,它等价于objective-c的 #pragma。

对第三个方法,也就是playerDidFinishPlaying()进行编程实现。首先,在viewController中添加变量。

 /// 记录当前播放歌曲在songs内的位置。
    var id = 0;

在didReceiveResults中,添加一行。

         self.id = 0;

给playerDidFinishPlaying添加处理逻辑。

    /**
        每当播放结束时调用
    */
    func playerDidFinishPlaying() {

        self.id+=1;
        println(self.id)

        //放在主线程,提高反应速度
        dispatch_async(dispatch_get_main_queue(), {
            () ->Void in
            UIApplication.sharedApplication().networkActivityIndicatorVisible = true
            let song = self.songs[self.id] as! NSDictionary
            let songURL = song["url"] as! String
            self.circularProgressView.stop()
            self.circularProgressView.audioURL = NSURL(string: songURL)
            self.circularProgressView.play()
            let imageUrl = song["picture"] as! String
            self.onSetImage(imageUrl)
            UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        })

    }

到这里,扫描面部后,能够放歌,并且当歌曲结束后,会自动切换歌曲。

但现在我们不知道,播放的歌曲是歌名和演唱者,所以,现在来添加这部分的操作代码。在viewController中添加:

    /**
     负责更新歌曲

    :param: song 需要更新的歌曲信息
    */

     func updateSong(song : NSDictionary){
            //update audio player
            let songURL =  song["url"] as! String
            self.circularProgressView.stop()
            self.circularProgressView.audioURL = NSURL(string: songURL)
            self.circularProgressView.play()

            //update image view
            let imageUrl = song["picture"] as! String
            self.onSetImage(imageUrl)

            //update song title --> label1
            label1.text = song["title"] as? String

            //update artist  --> label2
            label2.text = song["artist"] as? String
            label2.font = label2.font.fontWithSize(13)


            UIApplication.sharedApplication().networkActivityIndicatorVisible = false
        }

将更新歌曲的操作封装在这个函数中,所以,修改didReceiveResults方法。

    /**
        负责处理从网络上获取的数据

    :param: results 获取得到的数据
    */
    func didReceiveResults(results : NSDictionary){
        println("数据成功接收")
//        println(results)
        self.songs = results["song"] as! NSArray

        let song = self.songs[0] as! NSDictionary


        self.id = 0;

        //更新界面UI的操作,放在主线程,提高反应速度
        dispatch_async(dispatch_get_main_queue(), {
            () ->Void in

            self.updateSong(song)

        })

    }

同时不要忘记修改其它地方,将切换歌曲或者播放歌曲,都放在updateSong中,修改playerDidFinishPlaying。

    /**
        每当播放结束时调用
    */
    func playerDidFinishPlaying() {

        self.id+=1;
        println(self.id)

        //放在主线程,提高反应速度
        dispatch_async(dispatch_get_main_queue(), {
            () ->Void in
            UIApplication.sharedApplication().networkActivityIndicatorVisible = true
            let song = self.songs[self.id] as! NSDictionary
            //update song
            self.updateSong(song)
        })

    }

到现在,似乎完成的很不错了,但是有一个bug,可能你早有迷惑,我们扫描心情只是一次,提取的歌曲数量也是有限,如果歌曲列表songs中的歌曲都播放完毕了,怎么办? 如果不做处理,程序会crash。所以,需要在每次歌曲播放结束后,进行判断。

在ViewController中,添加一个枚举类型。

/**
    枚举类型,记录心情

- happy: 快乐的心情
- sad:   悲伤的心情
*/
enum Emotion{
    case happy
    case sad
}

在Viewcontroller类中,添加属性:

 /// 当前的心情
 var emotion : Emotion = Emotion.happy

更新歌曲播放结束后的处理方法playerDidFinishPlaying。

    /**
        每当播放结束时调用
    */
    func playerDidFinishPlaying() {

        self.id+=1;
//        println(self.id)

        //如果最后一首歌曲播放完毕,需要再次访问网络,获取资源
        if self.id == songs.count {
            switch emotion{
            case .happy :
                http.onSearch(happySongsURL)
            case .sad :
                http.onSearch(sadSongsURL)
            }
//            println("songs is over")
            self.id=0
        }

        //放在主线程,提高反应速度
        dispatch_async(dispatch_get_main_queue(), {
            () ->Void in
            UIApplication.sharedApplication().networkActivityIndicatorVisible = true
            let song = self.songs[self.id] as! NSDictionary
            //update song
            self.updateSong(song)
        })

    }

笔者注:欢迎非商业转载,但请一定注明出处

如果你认为这篇不错,也有闲钱,那你可以用支付宝随便捐助一快两块的,以慰劳笔者的辛苦:

3、swift开发iOS——swift数据类型

3、swift开发iOS——swift数据类型



Swift 数据类型

在程序语言编程时,需要使用各种数据类型来存储不同的信息。

变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。在声明变量时也可指定它的数据类型。所有变量都具有数据类型,以决定能够存储哪种数据。

内置数据类型

Swift 提供了非常丰富的数据类型,以下列出了常用了几种数据类型:

Int

一般来说,不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型Int,长度与当前平台的原生字长相同:

32位平台上,IntInt32长度相同。

64位平台上,IntInt64长度相同。

除非你需要特定长度的整数,一般来说使用Int就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,Int可以存储的整数范围也可以达到-2,147,483,648~2,647,大多数时候这已经足够大了。

UInt

Swift 也提供了一个特殊的无符号类型UInt,长度与当前平台的原生字长相同:

32位平台上,UIntUInt32长度相同。

64位平台上,UIntUInt64长度相同。

注意:

尽量不要使用UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用Int,即使你要存储的值已知是非负的。统一使用Int可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考类型安全和类型推断。

浮点数

浮点数是有小数部分的数字,比如3.141590.1-273.15

浮点类型比整数类型表示的范围更大,可以存储比Int类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:

Double表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。

Float表示32位浮点数。精度要求不高的话可以使用此类型。

注意:

Double精确度很高,至少有15位数字,而Float最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。

布尔值

Swift 有一个基本的布尔(Boolean)类型,叫做Bool。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,truefalse

字符串

字符串是字符的序列集合,例如:

"Hello,World!"

字符

字符指的是单个字母,例如:

"C"

可选类型

使用可选类型(optionals)来处理值可能缺失的情况。可选类型表示有值或没有值。

数值范围

下表显示了不同变量类型内存的存储空间,及变量类型的最大最小值:

类型 大小(字节) 区间值

Int8 1 字节 -127 127

UInt8 1 字节 0 255

Int32 4 字节 -2147483648 2147483647

UInt32 4 字节 0 4294967295

Int64 8 字节 -9223372036854775808 9223372036854775807

UInt64 8 字节 0 18446744073709551615

Float 4 字节 1.2E-38 3.4E+38 (~6 digits)

Double 8 字节 2.3E-308 1.7E+308 (~15 digits)

类型别名

类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义。语法格式如下:

typealias newname = type

例如以下定义了 Int 的类型别名为 Feet

typealias Feet = Int

现在,我们可以通过别名来定义变量:

import Cocoa


typealias Feet = Int

var distance: Feet = 100

print(distance)

我们使用 playground 执行以上程序,输出结果为:

100

类型安全

Swift 是一个类型安全(type safe)的语言。

由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。

import Cocoa


var vara = 42

vara = "This is hello"

print(vara)

以上程序,会在 Xcode 中报错:

error: cannot assign value of type 'String' to type 'Int'

vara = "This is hello"

意思为不能将 'String' 字符串赋值给 'Int' 变量。

类型推断

当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。

如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。

例如,如果你给一个新常量赋值42并且没有标明类型,Swift 可以推断出常量类型是Int,因为你给它赋的初始值看起来像一个整数:

let meaningOfLife = 42

// meaningOfLife 会被推测为 Int 类型

同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是Double

let pi = 3.14159

// pi 会被推测为 Double 类型

当推断浮点数的类型时,Swift 总是会选择Double而不是Float

如果表达式中同时出现了整数和浮点数,会被推断为Double类型:

let anotherPi = 3 + 0.14159

// anotherPi 会被推测为 Double 类型

原始值3没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为Double类型。

实例

import Cocoa


// vara 会被推测为 Int 类型

var vara = 42

print(vara)


// varB 会被推测为 Double 类型

var varB = 3.14159

print(varB)


// varC 也会被推测为 Double 类型

var varC = 3 + 0.14159

print(varC)

执行以上代码,输出结果为:

42

3.14159

3.14159

ios sqlite3数据库操作

ios sqlite3数据库操作

1.分别导入头文件和libsqlite3.dylib框架

#import <sqlite3.h>

2.创建数据库句柄

    sqlite3 *db;

3.用创建的句柄创建或打开数据库

    //打开数据库
    if (sqlite3_open([daPath UTF8String], &db) != SQLITE_OK) {
        sqlite3_close(db);
        NSLog(@"打开错误");
    }else{
        NSLog(@"ok");
    }

4.数据表操作方法

- (void)execSql:(NSString *)sql{
    char *err = nil;
    if (sqlite3_exec(db, [sql UTF8String], nil, nil, &err) != SQLITE_OK) {
        sqlite3_close(db);
        NSLog(@"%@ err:%s", sql, err);
    }else {
        NSLog(@"%@ ok", sql);
    }
}

5.创建数据表

-(void)createOrOpenTable{
    NSString *sqlCreateTable = @"CREATE TABLE IF NOT EXISTS Students (ID INTEGER PRIMARY KEY AUTOINCREMENT, name varchar(20), age INTEGER, school varchar(40))";
    [self execSql:sqlCreateTable];
}

6.在数据表中插入新数据

- (void)insertAValueWithName:(NSString *)aName andAge:(NSInteger)anAge andSchool:(NSString *)aSchool{
    NSString *sql1 = [NSString stringWithFormat:
                      @"INSERT INTO Students (name, age, school) VALUES (''%@'', ''%d'', ''%@'')"
                      , aName, anAge, aSchool];
    [self execSql:sql1];
}

7.获取数据表中的数据

- (NSMutableArray *)getPersons{
    NSString *sqlQuery = @"select * from Students";
    sqlite3_stmt *statement;
    
    NSMutableArray *personArray = [NSMutableArray array];

    if (sqlite3_prepare_v2(db, [sqlQuery UTF8String], -1, &statement, nil) == SQLITE_OK) {
        while (sqlite3_step(statement) == SQLITE_ROW) {
            char *name = (char *)sqlite3_column_text(statement, 1);
            NSString *nameString = [NSString stringWithUTF8String:name];
            
            int age = sqlite3_column_int(statement, 2);
            
            char *school = (char *)sqlite3_column_text(statement, 3);
            NSString *schoolString = [NSString stringWithUTF8String:school];
            Person *per = [[Person alloc] initWithName:nameString andAge:age andSchool:schoolString];
            
            [personArray addObject:per];
        }
    }else{
        NSLog(@"打开失败");
    }

    return personArray;
}


关于swift开发笔记8 - sqlite3数据的使用(xcode 7,ios9)的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于# 小贼音乐--Swift开发笔记 Step 1、#小贼音乐--Swift开发笔记 Step 2、3、swift开发iOS——swift数据类型、ios sqlite3数据库操作等相关内容,可以在本站寻找。

本文标签: