前言
其实大学期间学的主要是java语言,java主流的框架像Spring,springmvc,mybatis,springboot都学过,项目实践也有一些。另外前端的话最基本的三门语言html5,css,js肯定也是java开发必须要了解的,同时也有jquery这些前端框架,也了解过vue这门框架。所以总的来说本科期间都是朝着后端开发的方向发展。
只能说天不遂人愿,找工作稀里糊涂的来了ios开发,不过客户端开发也很有意思。至少不用管数据库那部分。
ios学习
ios学习包括object-c语言和swift语言,现在主流的还是oc语言,但是swift语言肯定会之后作为ios开发的主要语言,一些三方库和swift底层是oc写的,因此至少也要能看懂oc,毕竟语言之间都大差不差。
其实自学ios的人很少,为什么?我的理解第一个是因为设备问题。因为我们在上大学的时候,尤其是工科专业考虑软件兼容问题,大部分人都是选择PC,我身边用MAC的人也都是后面才换的,如果说其他方面比如说长期用apple产品的人肯定优先选择MAC,不乏有装逼的也用哈。这我就不得不吐槽一嘴,朋友圈两位大老爷们儿,对iPhone15各种尬吹,有种女生看到喜欢的男明星那种感觉。我最初用mac本也很生疏,最基本的一些操作都不清楚,触控板也玩不明白。另外,就我自学来看,ios开发自学免费的资源肯定是不如其他语言的,如果说不会科学上网更是如此。
基础部分
基础部分其实语言与语言之间差别很小,大同小异吧。当然上swift中还是有很多新的地方。学习基础部分的前两天,能从这门语言中看到java,python,js的影子。和c语言还是有很大不同的,不过有一定的语言基础学起来很快,这点毋庸置疑。
我相信很多人在学第一门语言的时候绝对知道菜鸟教程,所以基础部就是菜鸟教程,但是更加推荐使用苹果官方的教程。因为菜鸟教程就是抄的人家的,还不完整但也够用 Swift 教程 | 菜鸟教程 关于 Swift | Swift 编程语言中文教程(The Swift Programming Language)
UIKit
苹果后来出了swiftUI,但是初学者应该还是从uikit开始,这部分的资源极少,我用的一个比较老的,还是台湾的一个文档UIKit · Swift 起步走 这个教程有个缺点就是它已经老了,很多方法都被弃用了,需要自己去查查。
这部分就和前端差不多了,学过前端的应该很容易上手。没什么好说的,就是跟着学,忘了的话再去查,回去看。我自己学习时候瞎写的如下:GitHub - 299710583/UIKitTest也用这个复习了下git
Cocoapods工具
这个工具是用来管理三方库,ios开发中会用到一些很方便的三方库,这能够大大减少工作量,Cocoapods就是用来引入管理三方库的工具,类似maven管理工具。
需要取下载和安装Cocoapods这个很多教程,照着做就能完成。
cocoapods首次使用三方库
-
新建工程
-
在终端进入工程文件夹
-
终端输入pod init(安装了cocoapods的前提)
-
编辑podfile文件,vi Podfile
-
在Podfile文件中加入第三方库的依赖语法,保存退出
-
终端输入Pod install
-
完成之后,打开工程文件夹查看,打开.xcworkspace文件,完成!
常用的三方库
Alamofire 和SwiftJSON
alamofire这个库主要就是能够很方便用于网络请求。SwiftJSON这个三方库处理json非常方便,不用每一个都转化成[string?:any]的形式。具体的这个例子是一个天气的小demo不怎么规范,可以看下面网络请求部分,注释掉的就是用原始的方式请求:
//
// WeatherData.swift
// weather-demo
//
// Created by 曾卫 on 2024/5/6.
//
import Foundation
import Alamofire
import SwiftyJSON
class WeatherData{
var city: String?
var url: URL?
var json: [String:Any]?
var weather: String?
var temp_c: Int?
var humidity: Int?
var windDirection: String?
var windSpeed: Double?
var errors: String?
var cityZh: String?
var dates: [String]?
var maxTemps: [Double]?
var minTemps: [Double]?
var weathers: [String]?
var block: ((WeatherData) -> Void)?
init(city: String?,cityZh:String?) {
self.cityZh = cityZh
self.city = city
getWeatherData(city)
}
}
extension WeatherData{
func getWeatherData(_ city:String?){
guard let city = city else { return }
dates = []
maxTemps = []
minTemps = []
weathers = []
url = URL(string: "https://api.weatherapi.com/v1/forecast.json?key=2bedc09032474542ba132358243004&q=\(city)&days=7&aqi=no&alerts=no&lang=zh")!
// self.url = URL(string: "https://api.weatherapi.com/v1/current.json?key=2bedc09032474542ba132358243004&q=\(city)&aqi=no&alerts=no&lang=zh")
guard let url = url else { return }
//使用alamofire来实现
AF.request(url).response { response in
switch response.result{
case .success(let value):
let json = JSON(value!)
//取出当前天气
self.weather = json["current"]["condition"]["text"].string ?? " "
self.temp_c = json["current"]["temp_c"].int ?? 0
self.humidity = json["current"]["humidity"].int ?? 0
self.windDirection = json["current"]["wind_dir"].string ?? " "
self.windSpeed = json["current"]["wind_kph"].double ?? 0.0
//取出预测天气
if let array = json["forecast"]["forecastday"].array{
for item in array{
let element = JSON(item)
//取出日期
self.dates?.append(element["date"].string ?? "")
//取出最高最低气温
self.maxTemps?.append(element["day"]["maxtemp_c"].double ?? 0.0)
// print(element["day"]["maxtemp_c"].double ?? 0.0)
self.minTemps?.append(element["day"]["mintemp_c"].double ?? 0.0)
//取出天气
self.weathers?.append(element["day"]["condition"]["text"].string ?? " ")
}
}
self.block?(self)
case .failure(let error):
self.errors = error.localizedDescription
print("Error: \(error.localizedDescription)")
self.block?(self)
}
}
//不使用alamofire
// block?(self)
//
// let request = URLRequest(url: url)
// let session = URLSession.shared
// let semaphore = DispatchSemaphore(value: 0)
// let task = session.dataTask(with: request){ [self](data,response,error) in
// if let error = error {
// errors = "Error:\(error.localizedDescription)"
// print(errors ?? " ")
//
// }
// guard let httpResponse = response as? HTTPURLResponse,(200...299).contains(httpResponse.statusCode) else{
// errors = "Error:Invalid response"
// print(errors ?? " ")
// semaphore.signal()
// return
// }
// guard let data = data else{
// errors = "Error:Miss data"
// print(errors ?? " ")
// semaphore.signal()
// return
// }
//
// do {
// self.json = try JSONSerialization.jsonObject(with: data,options: []) as? [String:Any]
//
// //当前
// let current = self.json?["current"] as? [String:Any]
// //取出天气状态数据
// let condition = current?["condition"] as? [String:Any]
// let text = condition?["text"] as? String
// self.weather = text
//
// // 取出温度
// self.temp_c = current?["temp_c"] as? Int
//
// // 取出湿度
// self.humidity = current?["humidity"] as? Int
//
// // 取出风向
// self.windDirection = current?["wind_dir"] as? String
//
// // 取出风速
// self.windSpeed = current?["wind_kph"] as? Double
// // print(self.windSpeed ?? "ddddd")
//
// semaphore.signal()
//
// }catch let parseError{
// print("Error\(parseError.localizedDescription)")
// semaphore.signal()
// }
// }
// task.resume()
//
// semaphore.wait()
}
}
SwiftPullToResfresh
使用例子:
//下拉刷新,并且在里边写刷新要执行的是
myScrollView.spr_setTextHeader {
[weak self] in
let label = UILabel()
//这里之后要定义一个nextTime,用来记录最近更新时间
label.text = "最近更新时间\(String(describing: self?.nextTime ?? " "))"
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm:ss" // 仅保留时分秒部分
self?.nextTime = dateFormatter.string(from: currentDate)
label.textColor = .black
label.textAlignment = .center
label.frame = CGRect(x: 0, y: 10, width: 200, height: 20)
label.tag = 123
label.center = CGPoint(x: (self?.fullSize.width ?? 0) * 0.5, y: 10)
label.font = UIFont.systemFont(ofSize: 14)
self?.myScrollView.addSubview(label)
self?.weatherData = WeatherData(city: self?.cityName,cityZh: self?.cityZh)
self?.weatherData?.block = {[weak self] data in
guard let `self` = self else { return }
self.weatherData = data
refresh()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self?.myScrollView.spr_endRefreshing()
// 移除文字标签
if let labelToRemove = self?.myScrollView.viewWithTag(123) {
labelToRemove.removeFromSuperview()
}
}
}
AAInforgraphics
这个三方库用来做图标也是非常好使的。
func drawChart(){
chartView = AAChartView()
chartView?.frame = CGRect(x: 0, y: 0, width: fullSize.width, height: fullSize.height * 0.4)
chartView?.center = CGPoint(x: fullSize.width * 0.5, y: fullSize.height * 0.9)
chartView?.isClearBackgroundColor = true
guard let chartView = chartView else { return }
self.myScrollView.addSubview(chartView)
//初始化图标模型
chartModel = AAChartModel()
guard let chartModel = chartModel else { return }
//图标类型
chartModel.chartType(.line)
//图表标题
chartModel.title("天气预测")
chartModel.inverted(false)
chartModel.yAxisTitle("℃")
// chartModel.xAxisTitle("日期")
//浮动提示框
chartModel.legendEnabled(true)
chartModel.tooltipEnabled(true)
chartModel.tooltipValueSuffix("℃")
chartModel.markerRadius(0)
chartModel.categories(weatherData?.dates ?? [])
chartModel.colorsTheme(["#fe117c","#ffc069"])
chartModel.series([
AASeriesElement()
.name("最高气温")
.data(weatherData?.maxTemps ?? ["4","5"])
.toDic()!,
AASeriesElement()
.name("最低气温")
.data(weatherData?.minTemps ?? ["1","2"])
.toDic()!])
chartView.aa_drawChartWithChartModel(chartModel)
}
其他
Xcode软件快捷键
ctrl + B:光标向左移动
ctrl + F:光标向右移动
ctrl + P:光标向上移动(up)
ctrl + N:光标向下移动(down)
ctrl + A:光标移动到最左边 (记忆,a为所有字母第一个)
ctrl + E:光标移动到最右边(记忆,end)
ctrl + K:删除光标右边的所有
ctrl + H:向左删除一个,和退格一样的
ctrl + D:删除右边一个,类似于反过来的删除键
cmd + 退格:删除从后边删除所有的左边。mac通用的
ctrl + A:光标移动到最左边 之后 ctrl + K:删除光标右边的所有 就可以删掉一整行
option + 退格:删除一个单词或者一个汉字组成的词(mac通用的)
ctrl + i:代码规范化
ctrl + V:向下移动一部分
cmd + L:跳转到具体行数的快捷键
git和sourcetree
git命令简单的还是记住,记不住就用sourcetree来,对新手很友好。
还是有就是沙盒机制,viewcontroller生命周期,怎么实现不走main.stroyboard,自定义首先打开的页面,不同页面之间怎么传递数据,用闭包和代理。
网上找到的大部分教程都是基于xcode11,12,13,这些教程对xcode15如何删除storyboard不完全有用。
在删除storyboard(教程看xcode11、12、13,是一样的)之后需要在SceneDelegate中改变func scene方法
否则黑屏
guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) let nav = UINavigationController() nav.pushViewController(ViewController(), animated: true) window.rootViewController = nav self.window = window window.makeKeyAndVisible()
但是AppDelegate这个我开始重写了里边的方法func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) ->
Bool 重写为
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window!.backgroundColor = UIColor.white self.window!.rootViewController = ViewController() self.window!.makeKeyAndVisible() return true }
正常用,但是后面我注释掉,直接返回true,依然可以正常操作。