Swift UI Learning

发布于 / Swift / 0 条评论

AppDelegate 详解

先明白,每个iPhone应用程序都有一个UIApplication,UIApplication是iPhone应用程序的开始并且负责初始化并显 示 UIWindow,并负责加载应用程序的第一个UIView到UIWindow窗体中。UIApplication的另一个任务是帮助管理应用程序的 生命 周期,而UIApplication通过一个名字为UIApplicationDelegate的代理类来履行这个任务。尽管 UIApplication 会负责接收事件,而UIApplicationDelegate则决定应用程序如何去响应这些事 件,UIApplicationDelegate可以处理 的事件包括应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警 告),本文会介绍如何加载应用程序的UIView到 UIWindow以及如何利用UIApplicationDelegate处理系统事件。

通 常对于UIApplication读者是没必要修改它的,只需要知道UIApplication接收系统事件即可,而如何编写代码来处理这些系统事件 则 是程序员的工作。处理系统事件需要编写一个继承自UIApplicationDelegate接口的类,而 UIApplicationDelegate接 口提供生命周期函数来处理应用程序以及应用程序的系统事件,这些生命周期函数如下表所示:

1、- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@”当程序载入后执行”);
}
说明:当程序载入后执行,应用程序启动入口。只在应用程序启动时执行一次。也就是说在应用程序启动后,要执行的委托调用。application参数用来获取应用程序的状态、变量等,值得注意的是字典参数:(NSDictionary *)launchOptions,该参数存储程序启动的原因。

若用户直接启动,lauchOptions内无数据;

若由其他应用程序通过openURL:启动,则UIApplicationLaunchOptionsURLKey对应的对象为启动 URL(NSURL),UIApplicationLaunchOptionsSourceApplicationKey对应启动的源应用程序的 bundle ID (NSString);

若由本地通知启动,则UIApplicationLaunchOptionsLocalNotificationKey对应的是为启动应用程序的的本地通知对象(UILocalNotification);

若由远程通知启动,则UIApplicationLaunchOptionsRemoteNotificationKey对应的是启动应用程序的的远程通知信息userInfo(NSDictionary);

其他key还有UIApplicationLaunchOptionsAnnotationKey,UIApplicationLaunchOptionsLocationKey,
UIApplicationLaunchOptionsNewsstandDownloadsKey。

如果要在启动时,做出一些区分,那就需要在下面的代码做处理。比如:应用可以被某个其它应用调起(作为该应用的子应用),要实现单点登录,那就需要在启动代码的地方做出合理的验证,并跳过登录。
例子:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *url = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
if(url)
{
}
NSString *bundleId = [launchOptions objectForKey:UIApplicationLaunchOptionsSourceApplicationKey];
if(bundleId)
{
}
UILocalNotification * localNotify = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if(localNotify)
{
}
NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo)
{
}
}

UIView

作者:wangzz原文地址:http://blog.csdn.net/wzzvictory/article/details/10076323转载请注明出处

一、alpha
液晶显示器是由一个个的像素点组成的,每个像素点都可以显示一个由RGBA颜色空间组成的一种色值。其中的A就表示透明度alpha,UIView中alpha是一个浮点值,取值范围0~1.0,表示从完全透明到完全不透明。
当把alpha的值设置成0以后:
1、当前的UIView和subview都会被隐藏,而不管subview的alpha值为多少。
2、当前UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者
alpha的默认值是1.0。
另外,更改alpha值时,默认是有动画效果的,这是因为图层在Cocoa中是由Core Animation中CALayer表示的,该动画效果是CALayer的隐含动画。

二、hidden
该属性为BOOL值,用来表示UIView是否隐藏,默认值是NO。
当值设为YES时:
1、当前的UIView和subview都会被隐藏,而不管subview的hidden值为多少。
2、当前UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者
总之,同alpha为0时的显示效果相同。具体两者之间有什么区别就不清楚了,如果有知道的还望不吝赐教!

三、opaque
该属性为BOOL值,UIView的默认值是YES,但UIButton等子类的默认值都是NO。opaque表示当前UIView是否不透明,不过搞笑的是事实上它却决定不了当前UIView是不是不透明,比如你将opaque设为NO,该UIView照样是可见的(上文说过,是否可见是由alpha或hidden属性决定的),照理说为NO就表示透明,那就应该是不可见的呀?
卖个关子,先看下图:

前面讲过,显示器中的每个像素点都可以显示一个由RGBA颜色空间组成的色值,比如上图中有红色和绿色两个图层色块,对于没有交叉的部分,即纯红色和绿色部分来说,对应位置的像素点只需要简单的显示红或绿,对应的RGBA为(1,0,0,1)和(0,1,0,1)就行了,负责图形显示的GPU需要很小的计算量就可以确定像素点对应的显示内容。
问题是红色和绿色还有相交的一块,其相交的颜色为黄色。这里的黄色是怎么来的呢?原来,GPU会通过图层一和图层二的颜色进行图层混合,计算出混合部分的颜色,最理想情况的计算公式如下:
R = S + D * ( 1 – Sa )

其中,R表示混合结果的颜色,S是源颜色(位于上层的红色图层一),D是目标颜色(位于下层的绿色图层二),Sa是源颜色的alpha值,即透明度。公式中所有的S和D颜色都假定已经预先乘以了他们的透明度。

知道图层混合的基本原理以后,再回到正题说说opaque属性的作用。当UIView的opaque属性被设为YES以后,按照上面的公式,也就是Sa的值为1,这个时候公式就变成了:

R = S

即不管D为什么,结果都一样。因此GPU将不会做任何的计算合成,不需要考虑它下方的任何东西(因为都被它遮挡住了),而是简单从这个层拷贝。这节省了GPU相当大的工作量。由此看来,opaque属性的真实用处是给绘图系统提供一个性能优化开关!

按照前面的逻辑,当opaque属性被设为YES时,GPU就不会再利用图层颜色合成公式去合成真正的色值。因此,如果opaque被设置成YES,而对应UIView的alpha属性不为1.0的时候,就会有不可预料的情况发生,这一点苹果在官方文档中有明确的说明:
An opaque view is expected to fill its bounds with entirely opaque content—that is, the content should have an alpha value of 1.0. If the view is opaque and either does not fill its bounds or contains wholly or partially transparent content,the results are unpredictable. You should always set the value of this property to NO if the view is fully or partially transparent.
大家切记!!!!

弹窗

涉及到的组件:MessageBox ,Button,Action,self.present

即按钮绑定窗口事件,然后present去调用这个窗口

let title =  "Game Result";

let message = "Helllo!"

let messagebox = UIAlertController(title: title, message: message, preferredStyle: .alert)

let action = UIAlertAction(title: "OK", style: .default, handler: nil)   //handle是对"OK"按钮的处理事件,不处理为nil

messagebox.addAction(action)

self.present(messagebox, animated: true, completion: nil)   //animated为true即表示有动画效果

WKWebView

override func loadView() {

        let webConfiguration = WKWebViewConfiguration();

        webview = WKWebView(frame: .zero,configuration: webConfiguration)

        webview.uiDelegate = self

        view = webview    

    }

加载本地html

    override func viewDidLoad() {

        super.viewDidLoad()

        let htmlfilepath = Bundle.path(forResource: "aboutus", ofType: "html", inDirectory: Bundle.main.bundlePath)

        let htmldata = NSData(contentsOfFile: htmlfilepath!)

        let baseURL = NSURL(fileURLWithPath: Bundle.main.bundlePath)

        self.webview.load(htmldata! as Data, mimeType: "text/html", characterEncodingName: "UTF-8", baseURL: baseURL as URL)

    }

加载网页

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myURL = URL(string:"https://www.apple.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }}

GPS定位

import CoreLocation

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self;
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
        locationManager.requestAlwaysAuthorization();
        locationManager.startUpdatingLocation();
        
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations[locations.count - 1];
        if location.horizontalAccuracy > 0 {
            locationManager.stopUpdatingLocation();
            print("经度 = \(location.coordinate.longitude),纬度 = \(location.coordinate.latitude)");
            
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error)
    }


.list:

字典(Dictionary)

var dic1 = ["中国": "北京","英国": "伦敦"]
let dic2 = [String : String] = ["中国": "北京","英国": "伦敦"]

基于Alamofire的HTTP操作与JSON

一般网络操作会有如下几个方法:1.触发网络操作的方法 2.请求http的方法(一般包含JSON操作的成功与否的判断) 3.解析JSON数据包的方法(一般包含UI更新)

Weather APP的模板

import UIKit
import SwiftyJSON
import Alamofire


//    //MARK: - Networking
//    /***************************************************************/
//    
    func getWeatherData(url: String, parameters: [String : String]) {
        
        Alamofire.request(url, method: .get, parameters: parameters)
            .responseJSON { response in
                if response.result.isSuccess {

                    print("Sucess! Got the weather data")
                    let weatherJSON : JSON = JSON(response.result.value!)

                    self.updateWeatherData(json: weatherJSON)

                } else {
                    print("Error: \(String(describing: response.result.error))")
                    self.bitcoinPriceLabel.text = "Connection Issues"
                }
            }

    }


//    //MARK: - JSON Parsing
//    /***************************************************************/
//    
    func updateWeatherData(json : JSON) {
        
        if let tempResult = json["main"]["temp"].double {
        
        weatherData.temperature = Int(round(tempResult!) - 273.15)
        weatherData.city = json["name"].stringValue
        weatherData.condition = json["weather"][0]["id"].intValue
        weatherData.weatherIconName =    weatherData.updateWeatherIcon(condition: weatherData.condition)
        }
        
        updateUIWithWeatherData()
    }

泊学的模板

import Alamofire


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        Alamofire.request("https://httpbin.org/get", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
            .responseJSON(completionHandler: {response in
                print("=====================")
                switch response.result{
                case .success(let str):
                    print("\(str)")                
                case .failure(let err):
                    print("\(err)")
                    
                }
            })
  
    }
}

Segue与场景之间的传值

    @IBAction func Btn(_ sender: Any) {
        performSegue(withIdentifier: "GOGO", sender: self)
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "GOGO"{
            let destinationVC = segue.destination as! SecondViewController
            destinationVC.textInputPassedover = JTextFiled1.text!
            
            
        }
    }

//performSegue函数是实现一个跳转,带俩参数一个是Segue的Id另一个是发起者,
在实现一个控制器到另一个控制器之间的跳转之前会load控制器类中的prepare方法,在该方法中传值即可。

//最后在Segue目标类中改变组件属性即可


    var textInputPassedover :String?
    @IBOutlet weak var JLabel1: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.JLabel1.text = textInputPassedover;
        
    }

不同VC之间的数据传递(协议与委托)

从VC1转到VC2可以采用Segue 中的destination属性来访问VC2,但是如果想把VC2中的数值传回去,一方面我们想到在VC2中创建一个指向VC1的Segue进行传递,但实际上,VC2的这个Segue指向的是VC1的Copy,之后的所有Segue指向的都是前一个的Copy,A->B,B->C(Copy from A),C->D(Copy from B),而这个方式的代价便是不断消耗内存直至崩溃…

那么解决方式是啥呢,是协议与委托。

有两个VC,分别是VC1和VC2 ,现在需要当点击VC2中的某个btn时将VC2中的TextFiled中的字符串传给VC1.

1️⃣在VC2中自己写一个protocol(协议,类似于Java中的接口),并在里面声明一个返回值类型为String的方法。

2️⃣在VC2中创建一个类型为该protocol的变量,假设叫delegate

3️⃣回到VC1声明class后面实现该protocol,并且补全该protocol中的所有方法

4️⃣当VC1以通过某种方式,假设是按钮创建了一个Segue时会先调用被重写的prepare方法,因此在该方法中我们要指明VC2中的delegate属性为self(指向自己,这样VC2中如果有数据发送出来那么VC1可以收到)

5️⃣在VC2中利用delegate?.func调用函数传值

//下面是天气APP的实例

1️⃣
protocol ChangeCityDelegate {
  func userEnteredANewCityName(city: String)
}

2️⃣
var delegate: ChangeCityDelegate?

3️⃣
class WeatherViewController: UIViewController, CLLocationManagerDelegate, ChangeCityDelegate {
  func userEnteredANewCityName(city: String) {
    let params: [String: String] = ["q": city, "appid": APP_ID]
    getWeatherData(url: WEATHER_URL, parameters: params)
  }
}

4️⃣
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "changeCityName" {
      let destinationVC = segue.destination as! ChangeCityViewController
      destinationVC.delegate = self
    }
  }

5️⃣
//1 通过Text Field得到城市名称
let cityName = changeCityTextField.text!
    
//2 如果有一个delegate设置,则调用userEnteredANewCityName()方法
delegate?.userEnteredANewCityName(city: cityName)
    
//3 销毁CityViewController并返回到WeatherViewController
self.dismiss(animated: true, completion: nil)

基于NSCoder本地数据存储

注意被存储的class要满足Codable协议,项目源码:

https://github.com/wuruofeng/Swift_Learing

//
//  TodoListViewController.swift
//  TODO
//
//  Created by Rohlf W on 2019/1/26.
//  Copyright © 2019 Rohlf W. All rights reserved.
//

import UIKit

class TodoListViewController: UITableViewController {
    
    
    var itemArray = [Item]()
    let datafilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("Items.plist")
    

    override func viewDidLoad() {
        super.viewDidLoad()
//        let newItem = Item()
//        newItem.title = "购买水杯😴"
//        itemArray.append(newItem)
//        let newItem1 = Item()
//        newItem1.title = "吃药💊"
//        itemArray.append(newItem1)
//        let newItem2 = Item()
//        newItem2.title = "修改密码🎈"
//        itemArray.append(newItem2)
        loadItems()
    
        
//        if let items = defaults.array(forKey: "ToDoListArray") as? [Item]{
//            itemArray = items
//        }
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return itemArray.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoItemCell", for: indexPath)
        cell.textLabel?.text = itemArray[indexPath.row].title
        if itemArray[indexPath.row].done == false {
            cell.accessoryType = .none
        }else{
            cell.accessoryType = .checkmark
        }

        return cell
    }


    
    
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        itemArray[indexPath.row].done = !itemArray[indexPath.row].done
        
        saveItems()
        
        tableView.deselectRow(at: indexPath, animated: true)
        
    }

    
    @IBAction func addBtnPressed(_ sender: UIBarButtonItem) {
        var textFiled = UITextField()
        
        
        let alert = UIAlertController(title: "添加一个TODO项目", message: "", preferredStyle: .alert)
        
        alert.addTextField{
            (alertTextFiled) in
            alertTextFiled.placeholder = "创建一个新项目..."
            textFiled = alertTextFiled
        }
        let action = UIAlertAction(title: "添加项目", style: .default, handler: { (action) in
            //print("Success")
            let newItem = Item()
            newItem.title = textFiled.text!
            
            self.itemArray.append(newItem)
            self.saveItems()
            
            self.tableView.reloadData()
            })
        
        alert.addAction(action)
        present(alert,animated: true,completion: nil)
        
    
}
    
    
    
    func saveItems(){
        let encoder = PropertyListEncoder()
        do {
            let data = try encoder.encode(self.itemArray)
            try data.write(to: self.datafilePath!)
            
        }
        catch{
            print("Falled in encoding ...")
        }
        
    }
    
    func loadItems(){
        if let data = try? Data(contentsOf: self.datafilePath!){
            let decoder = PropertyListDecoder()
            do{
                itemArray = try decoder.decode([Item].self, from: data)
            }
            catch{
                print("解码错误")
            }
        }
    }
    
    
}

UIPicker

@IBAction func chooseImage(_ sender: Any) {

        let sharedImagePickerController = UIImagePickerController()
        sharedImagePickerController.delegate = self
        
        let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action:UIAlertAction) in
            sharedImagePickerController.sourceType = .camera
            self.present(sharedImagePickerController, animated: true, completion: nil)
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: {(action:UIAlertAction) in
            sharedImagePickerController.sourceType = .photoLibrary
            self.present(sharedImagePickerController, animated: true, completion: nil)
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        
        self.present(actionSheet, animated: true, completion: nil )
    }
转载原创文章请注明,转载自: 静沐暖阳 » Swift UI Learning
Not Comment Found