1. app间跳转
跳转到appstore
- 找到应用程序的描述链接,比如:http://itunes.apple.com/gb/app/yi-dong-cai-bian/id391945719?mt=8
- 然后将 http:// 替换为 itms:// 或者 itms-apps://:( itms://itunes.apple.com/gb/app/yi-dong-cai-bian/id391945719?mt=8, itms-apps:// itunes.apple.com/gb/app/yi-dong-cai-bian/id391945719?mt=8)
- 然后打开这个链接地址: [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms://itunes.apple.com/gb/app/yi-dong-cai-bian/id391945719?mt=8"]];
其它应用中打开app, 通过app的 URL Schemes
实验证明, 在浏览器中跳转到appstore页面的时候, 系统会自动拦截并打开appstore应用, 跳转到指定的APP页面.
浏览器中打开应用的话, 可以通过打开app相应的 URL Schemes 来打开app, 还可以传递参数, 以打开指定的页面.
2.关于开发中未使用的函数返回值的警告信息
//定义函数的时候, 函数前面添加如下的注解, 则未使用的返回值会得到警告信息
@warn_unused_result
//函数前面添加如下的注解, 未使用的返回值不会得到警告信息
@discardableResult
3.iflet, guardlet
swift开发也有一段时间了, 今天get一个iflet的新技能, 如下代码所示, iflet之后, 可以直接进行条件判断. 不得不说这个功能还是非常有用的, 在过去的一个swift项目中初次遇到这个问题, 由于没人指导只能再加个if判断来解决, 这是一个好方法!
iflet和guardlet都支持条件判断!
var num: Int? = 30
if let num = num, num > 30 {
print("num: \(num)")
}else{
print("num不符合条件")
}
4.app启动图和icon的尺寸
icon尺寸: notification@2x.png(40×40), notification@3x.png(60×60) spotlight5-11@2x.png(58×58), spotlight5-11@3x.png(87x87) spotlight7-11@2x.png(80×80), spotlight7-11@3x.png(120x120) appicon@2x.png(120×120), appicon@3x.png(180×180) appstore.png(1024x1024)
启动图尺寸: 640 × 1136 1242 × 2208 640 × 960 750 × 1334 iPhone X: 1125*2436
5.OptionSet
在Objective-C中, 我们可以这样定义一个enum, 然后我们可以通过 &, | 等符号将多个合并在一起形成一个集合Options, 在Objective-C中我们使用NS_OPTIONS
这样的类型.
在swift中我们也可以定义相似的类型, 不过是使用OptionSet
类型,如下声明一个WHHero
类型的方法如下. 通过声明一些静态常量来标记不同的状态.
public struct WHHero: OptionSet {
public var rawValue: UInt
public init(rawValue: UInt) {
self.rawValue = rawValue
}
public static let hero1 = WHHero(rawValue: 1 << 0)
public static let hero2 = WHHero(rawValue: 1 << 1)
public static let hero3 = WHHero(rawValue: 1 << 2)
public static let hero4 = WHHero(rawValue: 1 << 3)
public static let hero5 = WHHero(rawValue: 1 << 4)
}
OptionSet类型本身就是可包含一个也可以包含多个类型的OptionSet, 示例代码如下所示.
let h1: WHHero = .hero3
var h2: WHHero = [.hero1, .hero2, .hero4]
let h3: WHHero = .hero4
h2 == h3
h2.contains(h3) //判断是否包含
h2.insert(h1) //set中插入新的set
h2.remove(h1) //重set中移除指定的set
print(h1)
h1.rawValue
h2.rawValue
6.label的lineBreakMode
addrView.titleLabel?.lineBreakMode = .byTruncatingTail
7.iPhone7p, 太多url重定向报错
项目使用http测试没有任何问题, 切换到线上的https的时候所有网络请求都报错"太多url重定向", 这次解决方法: 1.关闭appstore, 2.清除safari缓存和浏览记录,3.重启手机. 4.删除重装app,好使了! 卧槽, 这是社么问题? 也是奇葩!
8.适配iOS 11
四行代码适配iOS 11中的ScrollView
. 以下代码放在Appdelegate
的didFinishLaunchingWithOptions
中即可.
if (@available(ios 11.0,*)) {
UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
UITableView.appearance.estimatedRowHeight = 0;
UITableView.appearance.estimatedSectionFooterHeight = 0;
UITableView.appearance.estimatedSectionHeaderHeight = 0;
}
9.where的用法, 给符合某种指定条件的类型添加扩展
extension ArraySlice where Element == String {
/// Returns a new string by concatenating the elements of the sequence,
/// adding the given separator between each element.
///
/// The following example shows how an array of strings can be joined to a
/// single, comma-separated string:
///
/// let cast = ["Vivien", "Marlon", "Kim", "Karl"]
/// let list = cast.joined(separator: ", ")
/// print(list)
/// // Prints "Vivien, Marlon, Kim, Karl"
///
/// - Parameter separator: A string to insert between each of the elements
/// in this sequence. The default separator is an empty string.
/// - Returns: A single, concatenated string.
public func joined(separator: String = default) -> String
}
10. 五分钟实现label轮播的广告
思路就是使用CATransition, 简单粗暴, 转场动画直接完事, 需要注意的是, 动画移动过程中, label边界可能会超出父类view的边界, 解决就是设置父类的clipToBounds = true
, 这样超出的就会被剪切掉, 完美!
这种可以实现从上到下, 从下到上, MoviIn, Puhs等效果, 如果文字比较长, 需要右到左展示, 额能需要解决scrollview实现方便一点. 就这样.
var ransitionAnimation: CATransition {
let ani = CATransition()
ani.type = kCATransitionPush
ani.subtype = kCATransitionFromTop
ani.duration = 0.3
ani.isRemovedOnCompletion = true
return ani
}
11. 关于swift中的锁和defer关键字
objc_sync_enter, objc_sync_exit
如下所示, 是一个模拟Objective-C中的dispatch_once的代码, 其中锁定使用了objc_sync_enter
这种方法, 使用objc_sync_enter
和 objc_sync_exit
包裹的代码会被有序、同步地执行。
但是,需要谨记,一旦 sync_enter
以后,整个应用就会被锁定,直至 sync_exit
。所以,在 lock 的代码区域中,要多加留意,看是否存在死锁的现象。
public extension DispatchQueue {
private static var _onceTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, closure:()->Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
closure()
}
}
defer
延迟执行, defer代码块里面的代码会在return之前执行, 使用defer的好处是方式忘记一些关键代码, 比如打开一个文件后, 可以在defer的代码块里面关闭文件, 防止忘记关闭文件.
12. where关键字的应用
扩展一个类, 指定实现Equatable
协议的类型才有扩展中的方法和变量. 这时候可以使用where
关键字做过滤.
// MARK: - 数组元素操作(AnyClass类型)
public extension Array where Array.Element : Equatable {
/// 移除数组中的一个指定元素
///
/// - Parameter obj: 指定的元素
public mutating func removeObject(_ obj: Array.Element) {
guard let idx = self.index(of: obj) else {
return
}
remove(at: idx)
}
}
13. 关于UICollectionView header和footer的悬停效果
iOS 9以后系统提供了一下两个属性可以方便的实现悬停效果, 考虑到iOS 9以前用户比例比较少, 所以可以放弃考虑了.
// Set these properties to YES to get headers that pin to the top of the screen and footers that pin to the bottom while scrolling (similar to UITableView).
@available(iOS 9.0, *)
open var sectionHeadersPinToVisibleBounds: Bool
@available(iOS 9.0, *)
open var sectionFootersPinToVisibleBounds: Bool
14. Cell高度自适应问题
自从第一次做就一直在纠结到底哪种方式计算自适应高度才是最合理的, ? , 总结两个自己最常用的方式.
ios8以后可以用这种方法:
//1.这总方法. 在cell中不能设置label高度的约束, 使其自适应即可
self.tableView.estimatedRowHeight = 150;//估算高度
self.tableView.rowHeight = UITableViewAutomaticDimension;
//注释掉这个方法
//func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return App.relSize(128)
// }
//2. 另一种方法就是计算高度, 使用masonry或者snapkit设置约束了.