swift笔记(一)

屏幕快照 2017-07-10 上午9.14.29.png
屏幕快照 2017-07-10 上午9.14.40.png

1.通过代码创建根控制器:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        // 1.创建window
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.backgroundColor = UIColor.whiteColor()
        // 2.设置根控制器
        window?.rootViewController = MainViewController()
        // 3.显示window
        window?.makeKeyAndVisible()
        
        return true
    }

2.添加视图控制器

override func viewDidLoad() {
        super.viewDidLoad()

        // 1.添加子控制器
        /*
        // 1.1创建子控制器
        // 注意: Swift开发中定义变量时候先用let(常量), 只有真正需要修改时才用var
        let vc = HomeTableViewController()
        // 1.2设置自控制的相关属性
        vc.tabBarItem.title = "首页"
        vc.tabBarItem.image = UIImage(named: "tabbar_home")
        vc.tabBarItem.selectedImage = UIImage(named: "tabbar_home_highlighted")
        
        // iOS7以后只需要设置tintColor, 那么图片和文字都会按照tintColor渲染
        tabBar.tintColor = UIColor.orangeColor()
        // 1.3将子控制器添加到UITabBarController中
        addChildViewController(vc)
        */
        
        // iOS7以后只需要设置tintColor, 那么图片和文字都会按照tintColor渲染
        tabBar.tintColor = UIColor.orangeColor()
        
        // 添加子控制器
        addChildViewControllers()
    }
    
    /// 添加所有子控制器
    func addChildViewControllers()
    {
        addChildViewController(HomeTableViewController(), title: "首页", imageName: "tabbar_home")
        addChildViewController(MessageTableViewController(), title: "消息", imageName: "tabbar_message_center")
        addChildViewController(DiscoverTableViewController(), title: "发现", imageName: "tabbar_discover")
        addChildViewController(ProfileTableViewController(), title: "我", imageName: "tabbar_profile")
    }

    // override代表重写父类的方法
    // Swift支持方法的重载, 也就是说只要方法的参数个数或者数据类型不相同, 那么系统就会认为是两个方法
    /// 添加一个子控制器
    func addChildViewController(childController: UIViewController, title: String, imageName: String) {
        
        // 1.2设置自控制的相关属性
//        childController.navigationItem.title = title
//        childController.tabBarItem.title = title
        
        // 该方法会由内向外的设置标题
        childController.title = title
        childController.tabBarItem.image = UIImage(named: imageName)
        childController.tabBarItem.selectedImage = UIImage(named: imageName + "_highlighted")
        
        
        // 1.3包装一个导航控制器
        let nav = UINavigationController(rootViewController: childController)
        // 1.4将子控制器添加到UITabBarController中
        addChildViewController(nav)
    }

3.打印


/*
打印LOG的弊端:
1.非常消耗性能
2.如果app部署到AppStore之后用户是看不到LOG的

所以
开发阶段: 显示LOG
部署阶段: 隐藏LOG
*/
// 函数的默认值: 如果调用者没有传递对应的参数, 那么系统就会使用默认值, 如果调用者传递了参数, 那么就会使用传递的参数
/*
 由于编译器可以通过赋值的类型自动推导出数据的真实类型, 所以在Swift开发中, 能不写数据类型就不写数据类型
 优点: 可以减少冗余代码
*/
/*
泛型
如果想在函数中使用泛型, 那么必须告诉系统者是一个泛型函数
func 函数名称<T>(形参列表) -> 返回值类型
{
}
message : T
T具体是什么类型由调用者来确定, 调用者传递的是什么类型, T就是什么类型
*/

func NJLog<T>(message: T, fileName: String = #file, methodName: String = #function, lineNumber: Int = #line)
{
    #if DEBUG
//    print("\((fileName as NSString).pathComponents.last!).\(methodName)[\(lineNumber)]:\(message)")
        print("\(methodName)[\(lineNumber)]:\(message)")
    #endif
}

4.命名空间

 /*
        guard 条件表达式 else {
//            需要执行的语句
//            只有条件为假才会执行{}中的内容
            return
        }
        guard可以有效的解决可选绑定容易形成{}嵌套问题
        */
        

/*
        Swift中新增了一个叫做命名空间的概念
        作用: 避免重复
        不用项目中的命名空间是不一样的, 默认情况下命名空间的名称就是当前项目的名称
        正是因为Swift可以通过命名空间来解决重名的问题, 所以在做Swift开发时尽量使用cocoapods来集成三方框架, 这样可以有效的避免类名重复
        正是因为Swift中有命名空间, 所以通过一个字符串来创建一个类和OC中也不太一样了, OC中可以直接通过类名创建一个类, 而Swift中如果想通过类名来创建一个类必须加上命名空间
        */

        

 /// 添加一个子控制器
    func addChildViewController(childControllerName: String?, title: String?, imageName: String?) {

        
        // 动态获取命名空间
        // 由于字典/数组中只能存储对象, 所以通过一个key从字典中获取值取出来是一个AnyObject类型, 并且如果key写错或者没有对应的值, 那么就取不到值, 所以返回值可能有值也可能没值, 所以最终的类型是AnyObject?
        guard let name =  NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as? String else
        {
            NJLog("获取命名空间失败")
            return
        }
        
        // 2.根据字符串获取Class
        var cls: AnyClass? = nil
        if let vcName = childControllerName
        {
            cls = NSClassFromString(name + "." + vcName)
        }
        
        // 3.根据Class创建对象
        // Swift中如果想通过一个Class来创建一个对象, 必须告诉系统这个Class的确切类型
        guard let typeCls = cls as? UITableViewController.Type else
        {
            NJLog("cls不能当做UITableViewController")
            return
        }
        // 通过Class创建对象
        let childController = typeCls.init()
        
        
        // 1.2设置自控制的相关属性
        childController.title = title
        if let ivName = imageName
        {
            childController.tabBarItem.image = UIImage(named: ivName)
            childController.tabBarItem.selectedImage = UIImage(named: ivName + "_highlighted")
        }
        
        // 1.3包装一个导航控制器
        let nav = UINavigationController(rootViewController: childController)
        // 1.4将子控制器添加到UITabBarController中
        addChildViewController(nav)
        
    }

5.动态加载

 /// 添加所有子控制器
    func addChildViewControllers()
    {
        
        // 1.根据JSON文件创建控制器
        // 1.1读取JSON数据
        guard let filePath =  NSBundle.mainBundle().pathForResource("MainVCSettings.json", ofType: nil) else
        {
            NJLog("JSON文件不存在")
            return
        }
        
        guard let data = NSData(contentsOfFile: filePath) else
        {
            NJLog("加载二进制数据失败")
            return
        }
        
        // 1.2将JSON数据转换为对象(数组字典)
        do
        {
            /*
             Swift和OC不太一样, OC中一般情况如果发生错误会给传入的指针赋值, 而在Swift中使用的是异常处理机制
             1.以后但凡看大 throws的方法, 那么就必须进行 try处理, 而只要看到try, 就需要写上do catch
             2.do{}catch{}, 只有do中的代码发生了错误, 才会执行catch{}中的代码
             3. try  正常处理异常, 也就是通过do catch来处理
                try! 告诉系统一定不会有异常, 也就是说可以不通过 do catch来处理
                     但是需要注意, 开发中不推荐这样写, 一旦发生异常程序就会崩溃
                     如果没有异常那么会返回一个确定的值给我们
        
                try? 告诉系统可能有错也可能没错, 如果没有系统会自动将结果包装成一个可选类型给我们, 如果有错系统会返回nil, 如果使用try? 那么可以不通过do catch来处理
            */
            
            let objc = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! [[String: AnyObject]]
            
            // 1.3遍历数组字典取出每一个字典
            for dict in objc
            {
                // 1.4根据遍历到的字典创建控制器
                let title = dict["title"] as? String
                let vcName = dict["vcName"] as? String
                let imageName = dict["imageName"] as? String
                addChildViewController(vcName, title: title, imageName: imageName)
            }
        }catch
        {
            // 只要try对应的方法发生了异常, 就会执行catch{}中的代码
            addChildViewController("HomeTableViewController", title: "首页", imageName: "tabbar_home")
            addChildViewController("MessageTableViewController", title: "消息", imageName: "tabbar_message_center")
            addChildViewController("DiscoverTableViewController", title: "发现", imageName: "tabbar_discover")
            addChildViewController("ProfileTableViewController", title: "我", imageName: "tabbar_profile")
        }
    }

6.变量类型推导

在 swift 开发中,对象的类型是自动推导的
对象的准确类型由创建对象时的代码决定
如果定义变量时,右侧代码具有歧义,可以在左侧以 :类型 指定变量的类型,例如:

// 个人推荐
let i: CGFloat = 10

也可以写成

var j = 10 as? CGFloat

如果某些方法返回的数据类型是 AnyObject/AnyClass,则需要在右侧使用 as 类型 表明类型,并且根据返回值是否是可选项,添加 ! 或者 ?,例如:

let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String

如果某些方法返回类型是 AnyObject/AnyClass,但是对象类型是动态生成的,也就是说,编码时同样无法确定改对象的准确类型,可以在左侧使用 : AnyObject 或者 : AnyClass 告诉编译器暂不处理,例如:

let cls: AnyClass = NSClassFromString(ns + "." + vcName)!

提示:as? 和 as! 是刚接触 swift 最令人烦恼的语法之一,苹果也在这个语法规则上多次做过调整,在学习时建议:

多用 option + click 查看对象信息
借助 Xcode 智能提示修改
多思考,多练习
swift里 as、as!、as?区别:http://www.jianshu.com/p/ebe29d97b5e9

7.加号按钮

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        
        tabBar.addSubview(composeButton)
        
        // 保存按钮尺寸
        let rect = composeButton.frame
        // 计算宽度
        let width = tabBar.bounds.width / CGFloat(childViewControllers.count)
        // 设置按钮的位置
        composeButton.frame = CGRect(x: 2 * width, y: 0, width: width, height: rect.height)
//        composeButton.frame = CGRectOffset(rect, 2 * width, 0)
    }

 /*
    public : 最大权限, 可以在当前framework和其他framework中访问
    internal : 默认的权限, 可以在当前framework中随意访问
    private : 私有权限, 只能在当前文件中访问
    以上权限可以修饰属性/方法/类
    
    在企业开发中建议严格的控制权限, 不想让别人访问的东西一定要private
    */
    // 如果给按钮的监听方法加上private就会报错, 报错原因是因为监听事件是由运行循环触发的, 而如果该方法是私有的只能在当前类中访问
    // 而相同的情况在OC中是没有问题, 因为OC是动态派发的
    // 而Swift不一样, Swift中所有的东西都在是编译时确定的
    // 如果想让Swift中的方法也支持动态派发, 可以在方法前面加上 @objc
    // 加上 @objc就代表告诉系统需要动态派发
    @objc private func compseBtnClick(btn: UIButton)
    {
        NJLog(btn)
    }
    // MARK: - 懒加载
    private lazy var composeButton: UIButton = {
        () -> UIButton
        in

     // 1.创建按钮
        let btn = UIButton(imageName:"tabbar_compose_icon_add", backgroundImageName: "tabbar_compose_button")
        
        // 2.监听按钮点击
        btn.addTarget(self, action: Selector("compseBtnClick:"), forControlEvents: UIControlEvents.TouchUpInside)
        
        return btn
    }()

8.Storyboard Reference

一种方法是在stroyboard拖一个storyboard reference,然后设置storyboard reference的属性。
第二种方法是选中要refenrence的界面,然后点击 Editor->Refactor to Storyboard,会生成新的storyboard。

屏幕快照 2017-07-10 上午10.41.58.png

这个只在ios9有效,以下的就可以用代码加载storyboard.
一个模块一个storyboard,这样不容易引起代码冲突。

9.访客视图

1.增加 用户登录标记

class BaseTableViewController: UITableViewController {

    ///  用户登录标记
    var userLogon = false

    override func loadView() {

        print(userLogon)

        super.loadView()
    }
}

2.根据用户登录标记判断是否加载默认视图

override func loadView() {

    userLogon = false

    userLogon ? super.loadView() : setupVisitorView()
}

///  设置访客视图
private func setupVisitorView() {
    view = VisitorLoginView()
}

3.添加导航栏按钮

///  设置访客视图
private func setupVisitorView() {
    view = VisitorLoginView()

    // 添加导航栏按钮
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "注册", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "登录", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
}

4.新建 VisitorLoginView.swift 继承自 UIView

///  访客登录视图
class VisitorLoginView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.redColor()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

5.添加界面元素

///  设置 UI 控件
private func setupUI(){
        // 1. 添加控件
        addSubview(iconView)
        addSubview(homeIconView)
        addSubview(messageLabel)
        addSubview(registerButton)
        addSubview(loginButton)
    }

// MARK: - 界面元素懒加载
  /// 背景图标
    private lazy var iconView: UIImageView = {
        let iv = UIImageView(image: UIImage(named: "visitordiscover_feed_image_smallicon"))
        return iv
        }()

    /// 小房子
    private lazy var homeIconView: UIImageView = {
        let iv = UIImageView(image: UIImage(named: "visitordiscover_feed_image_house"))
        return iv
        }()

    /// 消息文字
    private lazy var messageLabel: UILabel = {
        let label = UILabel()
        label.text = "关注一些人,回这里看看有什么惊喜"
        label.textColor = UIColor.darkGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.numberOfLines = 0
        label.sizeToFit()
        return label
        }()

    /// 注册按钮
    private lazy var registerButton: UIButton = {
        let btn = UIButton()
        btn.setTitle("注册", forState: UIControlState.Normal)
        btn.setBackgroundImage(UIImage(named: "common_button_white_disable"), forState: UIControlState.Normal)
        btn.setTitleColor(UIColor.orangeColor(), forState: UIControlState.Normal)
        return btn
        }()

    /// 登录按钮
    private lazy var loginButton: UIButton = {
        let btn = UIButton()
        btn.setTitle("登录", forState: UIControlState.Normal)
        btn.setBackgroundImage(UIImage(named: "common_button_white_disable"), forState: UIControlState.Normal)
        btn.setTitleColor(UIColor.orangeColor(), forState: UIControlState.Normal)
        return btn
        }()

6.设置自动布局

// 设置布局
        // 2.1背景图标
        iconView.xmg_AlignInner(type: XMG_AlignType.Center, referView: self, size: nil)

        // 2.3小房子
        homeIconView.xmg_AlignInner(type: XMG_AlignType.Center, referView: self, size: nil)
        // 2.4消息文字
        messageLabel.xmg_AlignVertical(type: XMG_AlignType.BottomCenter, referView: iconView, size: nil)
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 224))
        // 2.5注册按钮
        registerButton.xmg_AlignVertical(type: XMG_AlignType.BottomLeft, referView: messageLabel, size: CGSize(width: 100, height: 35), offset: CGPoint(x: 0, y: 20))
        // 2.6登录按钮
        loginButton.xmg_AlignVertical(type: XMG_AlignType.BottomRight, referView: messageLabel, size: CGSize(width: 100, height: 35), offset: CGPoint(x: 0, y: 20))

7.添加遮罩图片

    /// 遮罩图片
    // 注意系统有一个叫做maskView的属性, 属性名称不能叫做maskView
    private lazy var maskIconView: UIImageView = {
        let iv = UIImageView(image: UIImage(named: "visitordiscover_feed_mask_smallicon"))

        return iv
        }()

8.遮罩图片自动布局

    // 2.2遮罩
    maskIconView.xmg_Fill(self)

9.可以通过xib创建view

import UIKit

class VisitorView: UIView {
    /// 设置访客视图上的数据
    /// imageName需要显示的图标
    /// title需要显示的标题
    func setupVisitorInfo(imageName: String? , title: String)
    {
        // 1.设置标题
        titleLabel.text = title
        
        // 2.判断是否是首页
        guard let name = imageName else
        {
            // 没有设置图标, 首页
            // 执行转盘动画
            startAniamtion()
            
            return
        }
    
        // 3.设置其他数据
        // 不是首页
        rotationImageView.hidden = true
        
        iconImageView.image = UIImage(named: name)
        
    }
    
    /// 转盘旋转动画
    private func startAniamtion()
    {
        // 1.创建动画
       let anim =  CABasicAnimation(keyPath: "transform.rotation")
        
        // 2.设置动画属性
        anim.toValue = 2 * M_PI
        anim.duration = 5.0
        anim.repeatCount = MAXFLOAT
        
        // 注意: 默认情况下只要视图消失, 系统就会自动移除动画
        // 只要设置removedOnCompletion为false, 系统就不会移除动画
        anim.removedOnCompletion = false
        
        // 3.将动画添加到图层上
        rotationImageView.layer.addAnimation(anim, forKey: nil)
    }

    class func visitorView() ->VisitorView {
        return NSBundle.mainBundle().loadNibNamed("VisitorView", owner: nil, options: nil).last as! VisitorView
    }

}

10.UIButton+Extension.swift

import UIKit

extension UIButton
{
    
    /*
    如果构造方法前面没有convenience单词, 代表着是一个初始化构造方法(指定构造方法)
    如果构造方法前面有convenience单词, 代表着是一个便利构造方法
    
    指定构造方法和便利构造方法的区别
    1.指定构造方法中必须对所有的属性进行初始化
    2.便利构造方法中不用对所有的属性进行初始, "因为便利构造方法依赖于指定构造方法"
    一般情况下如果想给系统的类提供一个快速创建的方法, 就自定义一个便利构造方法
    */
    convenience init(imageName: String, backgroundImageName: String)
    {
        
        self.init()
        
        // 2.设置前景图片
        setImage(UIImage(named: "tabbar_compose_icon_add"), forState: UIControlState.Normal)
        setImage(UIImage(named: "tabbar_compose_icon_add_highlighted"), forState: UIControlState.Highlighted)
        // 3.设置背景图片
        setBackgroundImage(UIImage(named: "tabbar_compose_button"), forState: UIControlState.Normal)
        setBackgroundImage(UIImage(named: "tabbar_compose_button_highlighted"), forState: UIControlState.Highlighted)
        
        // 4.调整按钮尺寸
        sizeToFit()
    }
}

11.按钮图片切片
点击ShowSlicing进行切


WechatIMG1.jpeg

12.代理

/*
通知 : 层级结构较深
代理 : 父子 , 方法较多时候使用
block: 父子, 方法较少时使用(一般情况一个方法)
*/
protocol VisitorViewDelegate: NSObjectProtocol
{
    // 默认情况下协议中的方法都是必须实现的
    func visitorViewDidClickLoginBtn(visitor: VisitorView)
    func visitorViewDidClickRegisterBtn(visitor: VisitorView)
}

// 和OC一样代理属性必须使用weak修饰
weak var delegate: VisitorViewDelegate?

@IBAction func registerBtnClick(sender: AnyObject) {
        // 和OC不一样, Swift中如果简单的调用代理方法, 不用判断代理能否响应
        delegate?.visitorViewDidClickRegisterBtn(self)
    }

 @IBAction func loginBtnClick(sender: AnyObject) {
        delegate?.visitorViewDidClickLoginBtn(self)
    }
------------------------------------------------
// 2.设置代理
visitorView?.delegate = self
extension BaseTableViewController: VisitorViewDelegate
{
    func visitorViewDidClickLoginBtn(visitor: VisitorView)
    {
        NJLog("")
    }
    func visitorViewDidClickRegisterBtn(visitor: VisitorView)
    {
        NJLog("")
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容