layer.shouldRasterize
shouldRasterize instructs Core Animation to cache the layer contents as an image.
栅格化,设置为true则Core Animation将layer.contents渲染成一张图片缓存下来备用,不再刷新重绘视图,从而提高效率
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
layer.anchorPoint
设置layer.anchorPoint.x 要在设置layer.frame之前
UIViewController-自定义初始化方法
init(sideMenu: UIViewController, center: UIViewController) {
menuViewController = sideMenu
centerViewController = center
super.init(nibName: nil, bundle: nil)
}
CAGradientLayer
debug UIView Hierarchy
NSLayoutConstraint
// fixed width constraint:
let _ = NSLayoutConstraint(item: iv, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 50)
// relative width constraint
let widthCons = NSLayoutConstraint(item: iv, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: 1/3, constant: -50)
代码查找约束
for cons in titleLabel.superview!.constraints {
if cons.firstItem as? UIView == titleLabel && cons.firstAttribute == .centerX{
cons.constant = isMenuOpen ? 100 : 0
break
}
}
swift3 CGAffineTransform
view.transform = CGAffineTransform(scaleX: 1, y: 0.1)
.concatenating(CGAffineTransform(translationX: 0, y: off))
Array扩展
extension Array where Element: Comparable{
}
guard & where 配合使用
guard let dividend = dividend where dividend != 1, let divisor = divisor where divisor != 0 else {
return .None
}
播放声音
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate) //震动
获取String高度/宽度
let rect = (textView.text as NSString).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: textView.font!], context: nil)
UIColor-16进制
public convenience init(hex: Int){
self.init(red: CGFloat((hex >> 16) & 0xff), green: CGFloat((hex >> 8) & 0xff), blue: CGFloat(hex & 0xff), alpha: 1)
}
UITableView分割线设置问题
// 注意在initWithFrame/initWvithCoder里设置才起作用
v.separatorStyle = .none
UITableView/UICollectionView阴影设置问题
v.clipsToBounds = false //必须为false才行,默认是true
// cell也要与view设置同样大的圆角,同时bgcolor设置为nil
UICollectionViewCell/UITableViewCell布局layoutMargins设置注意
// 必须设置了contentView.layoutMargins才起作用
contentView.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
Xcode8一直打印AQDefaultDevice (173): skipping input stream
libc++abi.dylib`__cxa_throw: 使用[AVAudioPlayer play]会产生__cxa_throw异常
Swfit.AnyClass获取
public var appName: String{
guard let dict = Bundle.main.infoDictionary,
let name = dict["CFBundleName"] as? String else{
return ""
}
return name
}
func SwiftClassFromNameString(_ className: String) -> AnyClass?{
let name = "\(appName).\(className)"//这里要加上AppName.
return NSClassFromString(name)
}
WKWebView与JS交互
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
let user = WKUserContentController()
user.add(self, name: "Test")
config.userContentController = user
let wk = WKWebView(frame: view.bounds, configuration: config)
wk.load(URLRequest(url: Bundle.main.url(forResource: "test.html", withExtension: nil)!))
view.addSubview(wk)
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
JS判断客户端类型
// 01
// 02
UIWebView/WKWebView视频播放问题
allowsInlineMediaPlayback = true
mediaPlaybackRequiresUserAction = !UIDevice.current.isIpad //iPad得设置为false
状态栏隐藏
app.setStatusBarHidden(true, with: .fade) //9.0以前
// 或
override var prefersStatusBarHidden: Bool{
return true
}
View指定圆角
@IBInspectable
public var topLeft: Bool = false{
didSet{
setNeedsDisplay()
}
}
@IBInspectable
public var bottomLeft: Bool = false{
didSet{
setNeedsDisplay()
}
}
@IBInspectable
public var topRight: Bool = false{
didSet{
setNeedsDisplay()
}
}
@IBInspectable
public var bottomRight: Bool = false{
didSet{
setNeedsDisplay()
}
}
@IBInspectable
public var radius: CGFloat = 0{
didSet{
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
var corners: UIRectCorner = []
if topLeft {
corners.insert(.topLeft)
}
if bottomLeft {
corners.insert(.bottomLeft)
}
if topRight {
corners.insert(.topRight)
}
if bottomRight {
corners.insert(.bottomRight)
}
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
maskLayer.frame = rect
layer.mask = maskLayer
}
clipsToBounds和layer.masksToBounds对shadow效果的影响
- 注意true、false值对shadow效果的影响
- 注意layer.cornerRadius和其他border属性对shadow的影响
iOS10.3应用内动态替换AppIcon
@IBOutlet weak var segment: UISegmentedControl!
fileprivate let icons = [
"AppIcon1",
"AppIcon2"
]
override func viewDidLoad() {
super.viewDidLoad()
// 上次设置的图标名,默认为nil
if let name = UIApplication.shared.alternateIconName,
let i = icons.index(of: name){
print(name)
segment.selectedSegmentIndex = i+1
}
}
@IBAction func changeIcon(_ sender: UISegmentedControl){
let app = UIApplication.shared
let can = app.supportsAlternateIcons
if can {
let index = sender.selectedSegmentIndex
// nil时为默认图标Primary Icon
let name = index == 0 ? nil : icons[index-1]
app.setAlternateIconName(name, completionHandler: { (error) in
let info = error != nil ? "失败" : "成功"
print("更好图标: \(info)")
})
}
else{
print("不支持 AppIcon 动态替换")
}
}
UIView按下样式
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
// 背景色
backgroundColor = mcolors.gray.withAlphaComponent(0.2)
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
// 背景色
backgroundColor = mcolors.white
}
UICollectionViewCell的shadow问题
cell.layer.masksToBounds = false; //必须为false否者阴影没有效果
cell.layer.contentsScale = [UIScreen mainScreen].scale;
cell.layer.shadowOpacity = 0.75f;
cell.layer.shadowRadius = 4.0f;
cell.layer.shadowOffset = CGSizeMake(0,0);
cell.layer.shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds].CGPath;
//设置缓存
cell.layer.shouldRasterize = YES;
//设置抗锯齿边缘
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
点击status bar上的“返回 xxx”应用
的处理,刷新controller数据
- 注意,之前的vc将不再调用viewWillAppear方法,需要手动利用通知中心处理事件
func applicationWillEnterForeground(_ application: UIApplication) {
// 通知
NotificationCenter.default.post(name: .xxx, object: nil)
}
The Copy Bundle Resources build phase contains this target's Info.plist
问题
关于输入框键盘遮挡动画的一种不错方法
- 封装包含或基于UITextField的控件
// 加入键盘监听
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
// 处理键盘事件
-(void)keyboardWillShow: (NSNotification *)noti{
CGRect frame = [noti.userInfo[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat y = UIScreen.mainScreen.bounds.size.height - frame.size.height;
CGFloat bottom = CGRectGetMaxY(self.frame);
// 只有输入框被键盘遮挡时才调用
if (bottom > y) {
CGFloat off = bottom - y;
CGFloat duration = [noti.userInfo[@"UIKeyboardAnimationDurationUserInfoKey"] floatValue];
[_delegate inputView:self shouldUpdatePositionY:off duration:duration];
}
}
-(void)keyboardWillHide: (NSNotification *)noti{
CGFloat duration = [noti.userInfo[@"UIKeyboardAnimationDurationUserInfoKey"] floatValue];
[_delegate inputView:self shouldUpdatePositionY:0 duration:duration];
}
// 代理方法,改变约束值,进行动画
-(void)inputView:(HYLoginInputView *)inputView shouldUpdatePositionY:(CGFloat)offsetY duration:(NSTimeInterval)duration{
// 存储变量,变化值
_offYKeyboard = offsetY;
[UIView animateWithDuration:duration animations:^{
[self layoutSubviews]; //注意在UIViewController中调用[self layoutIfNeeded];进行重新布局
}];
}
// 更新布局
-(void)layoutSubviews{
[super layoutSubviews];
[_userNameInput mas_updateConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(@(offX));
make.trailing.equalTo(@(-offX));
make.centerY.mas_equalTo(self).offset(-_offYKeyboard); //键盘变化数值
make.height.equalTo(@80);
}];
}
关于Assets中image的Slicing
[The app delegate must implement the window property if it wants to use a main interface]解决
- ✅ AppDelegate中设置
var window: UIWindow!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window.rootViewController = xxx
return true
}
- ❌ 不要试图手动维护某个window,并设置为keyWindow,否则导致navigationBar的高度为44或横竖屏显示错误的问题,如:
private let window = UIWindow(frame: UIScreen.main.bounds)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window.rootViewController = xxx
return true
}
[POST git-receive-pack (chunked)]解决
[http]
postBuffer = 524288000
默认Xcode设置
xcode-select --print-path //查看原先路径
sudo xcode-select --switch
/Applications/Xcode8.3.2/Xcode8.3.2.app/Contents/Developer //新路径
横竖屏控制UICollectionView的不同尺寸展示
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
//改变布局 size,走UICollectionViewDelegateFlowLayout方法
collectionView?.collectionViewLayout.invalidateLayout()
//刷新数据 cell,走UICollectionViewDataSource方法
collectionView?.reloadData()
}
// 尺寸控制
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let num: CGFloat = app.statusBarOrientation.isLandscape ? 5 : 4
let w = (view.bounds.width - (num+1)*itemSpace) / num
return CGSize(width: w, height: w)
}
// 显示个数控制
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let num = app.statusBarOrientation.isLandscape ? 6 : 5
let count = data[section].items.count
if count > num {
return num
}
return count
}
It looks like git-am is in progress. Cannot rebase
cd 到工程根目录
执行rm -rf .git/rebase-apply
利用CIDetector识别图中的二维码
- 只适用于真机
- iOS5.0及以上
// 截屏图片
let screen = UIScreen.mainScreen()
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, screen.scale);
self.view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext();
// 识别
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
let ciimage = CIImage(CGImage: image.CGImage!)
let features = detector.featuresInImage(ciimage)
if let feature = features.first as? CIQRCodeFeature{
let str = feature.messageString
print("result: \(str)")
}
HUD提示view被键盘遮挡的解决方法
- 原因:将view加在了
UIApplication.shared.keyWindow
上,而键盘弹出时又是一个新的类型为UIRemoteKeyboardWindow
的窗口 - 解决:每次去动态计算获取相应的
keyWindow()
func keyWindow() -> UIWindow{
var window = app.keyWindow!
for w in app.windows{
let name = NSStringFromClass(w.classForCoder)
if name == "UIRemoteKeyboardWindow"{
window = w
break
}
}
return window
}
TableView删除cell问题小记
cell.configureCell(data: classes[indexPath.row]) {[unowned self] (data) in
var index: IndexPath!
// 注意这里存储的indexPath将不再有用,因为随着cell的删除,indexPath值是变化的,
// 除非你自己手动在删除cell后reloadData(),但那样会失去动画效果
for (i,e) in self.classes.enumerated(){
if e.id == data.id{
index = IndexPath(row: i, section: 0)
break
}
}
self.classes = self.classes.filter{
$0.id != data.id
}
self.tableView.deleteRows(at: [index], with: .automatic)
}
TabBar 相关尺寸
icon: <= 30x30px 一般: 26x26px
height: 49px = 48px + 1px分割线
fontSize: 12px
UITextField限定输入长度
extension RegisterVC: UITextFieldDelegate{
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.length == 0 { //删除键
return true
}
if textField == xxxTF && text.length > 10 {
return false
}
return true
}
}
Swift3.0 private、fileprivate、internal、public、open修饰符
private 定义的方法和属性,只能是
该类的对象
可以访问,类的extension
和子类对象
中均无法访问。fileprivate 顾名思义,只在当前的.swift文件中是私有的,可以在多个文件中定义同名的变量值。
internal 是默认的修饰符,可在当前整个工程源码所在的所有文件中均可以访问,常用来定义一些全局的宏变量或非法,通常省略不写。
public 只能在module内部被inherit和override
open 任何地方均可访问和override
Swift 参数是Float或Int类型的函数定义
func fo(_ value: T) where T: ExpressibleByIntegerLiteral, T: ExpressibleByFloatLiteral {
print(value)
}
Swift 输出函数名、类名、方法所在行号
func fo(name: String = #function, line: Int = #line, file: String = #file) {
print("\(file.lastPathComponent.deletingPathExtension) - \(name) - \(line)")
}
Swift3.0生成二维码图片
public extension UIImage {
public class func createQRCode(code: String, width: CGFloat, height: CGFloat) -> UIImage? {
let data = code.data(using: String.Encoding.isoLatin1, allowLossyConversion: false)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel")
// inputCorrectionLevel 是一个单字母(@"L", @"M", @"Q", @"H" 中的一个),表示不同级别的容错率,默认为 @"M"
// 错误修正容量 L水平 7%的字码可被修正
// M水平 15%的字码可被修正
// Q水平 25%的字码可被修正
// H水平 30%的字码可被修正
// 所以很多二维码的中间都有头像之类的图片但仍然可以识别出来就是这个原因
if let QRCodeImage = filter.outputImage {
//消除模糊
let scaleX = width/QRCodeImage.extent.size.width
let scaleY = height/QRCodeImage.extent.size.height
let transformedImage = QRCodeImage.applying(CGAffineTransform.init(scaleX: scaleX, y: scaleY))
return UIImage(ciImage: transformedImage)
} else {
return nil
}
}else {
return nil
}
}
}
StoryBoard上的UITableViewController中的static cell无法设置layoutMargins
如图设置cell元素约束的时候,必须考虑默认的值为8的margin
关于storyboard的unwind
//unwind一定是定义在当前页面vc的来源vc中,
//如vc2是由vc1导航push进来的,那么该unwind方法就应该在vc1中,而不是v2中
@IBAction func unwindForVC1(_ sender: UIStoryboardSegue){
}
MathJax数学表达式解析
hidesBottomBarWhenPushed=true使得view在布局变化时往下掉的问题
解决方法:
tabBar.isTranslucent = false //设置为不透明
同样适合解决:navigationController.toolBar.hidden = false出现的同样问题
xib或storyboard自动布局
当需要根据子view的高度压缩或拉伸的时候,就得设置各个view的
Hugging Priority
和Compression Resistance Priority
值越大越难被拉伸Hugging
或压缩Compression
要实现如图的效果则需要如下设置:
则布局设置优先级为:
点击view隐藏键盘的2种方法
//1. 当前view的touchesBegan方法
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
endEditing(true)
}
//2. 找不到controller或editing事件不在当前view中
UIApplication.shared.keyWindow?.endEditing(true)
brew update
sudo chmod -R g+w /usr/local
brew update
libxml2.tbd库引入问题解决
报错: 'libxml.h' file not found with
include, use "quotes" instead.
解决方法
Podfile编写
inhibit_all_warnings!
target 'DemoKissXML' do
platform :ios, '7.0'
pod 'KissXML'
end
- 执行命令:
pod setup
,再执行pod install
,每次改变Podfile内容,执行pod update
StoryBoard上自动布局约束设置
指定UIView的LayoutMargins
// 默认为8dp - 定义了view的内边距
view.layoutMargins = UIEdgeInsetsMake(20, 20, 20, 20)
UIWebView和JS交互一种新方案:
// 通过JS向body中新插入一个iframe标签,就会触发OC的webView shouldStartLoadWithRequest方法,
// 从而传递来自html的参数达到和UIWebView交互的目的
//JS方法
// OC
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSURL * url = [request URL];
if ([[url scheme] isEqualToString:@"xxx"]) {
// do something...
return NO;
}
return YES;
}
AppStore构建版本显示【缺少合规证明】
:
在info.plist中添加下面的键值
ITSAppUsesNonExemptEncryption
Masonry中iOS10宏支持iOS7
// 在MASUtilities.h中加入
#define NS_NOESCAPE __attribute__((noescape))
自定义UIWebView右键菜单
// 自定义MyWebView,重写init方法
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
// 这里自定义menu选项
UIMenuItem *copy = [[UIMenuItem alloc] initWithTitle:@"拷贝" action:@selector(copy:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:@[copy]];
}
return self;
}
// 重写方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
// 除了自定义menu的事件方法外,其他都不执行
if (action == @selector(copy:)) {
return YES;
}
return NO;
}
// copy事件
- (void)copy: (id)sender{
[self copy: sender];
}
UIWebView网页文字下划线、标记颜色JS
function stylizeHighlightedString() {
var range = window.getSelection().getRangeAt(0);
var selectionContents = range.extractContents();
var span = document.createElement("span");
span.appendChild(selectionContents);
// 点击标记的文字事件
span.setAttribute("onclick","alert('划过线的文字');");
// 标记颜色
// span.style.backgroundColor = "rgba(255,0,0,0.5)";
// 下划线
span.style.borderBottom = "2px solid red";
range.insertNode(span);
}
UIWebView背景透明
// 前提是不能设置webview的分页模式为水平模式【.LeftToRight或.RightToLeft】
webView.backgroundColor = [UIColor clearColor];
webView.opaque = NO;
iOS设备分辨率【全】
【iPhone】
iPhone 1G 320x480
iPhone 3G 320x480
iPhone 3GS 320x480
iPhone 4 640x960
iPhone 4S 640x960
iPhone 5 640x1136
iPhone 5S 640x1136
iPhone 5C 640x1136
iPhone 6 750x1334
iPhone 6 Plus 1080x1920 (开发应按照1242x2208适配)
iPhone 6S 750x1334
iPhone 6S Plus 1080x1920 (开发应按照1242x2208适配)
【iPod Touch】
iPod Touch 1G 320x480
iPod Touch 2G 320x480
iPod Touch 3G 320x480
iPod Touch 4G 640x960
iPod Touch 5G 640x1136
【iPad】
iPad 1 1024x768
iPad 2 1024x768
The New iPad 2048x1536
iPad mini 1024x768
iPad 4 2048x1536
iPad Air 2048x1536
iPad mini 2 2048x1536
iPad Air 2 2048x1536
iPad mini 3 2048x1536
iPad mini 4 2048x1536
iPad Pro 2732x2048
Bugly自动上传符号表脚本
#!/bin/sh
#
# Copyright 2016 Bugly, Tencent. All rights reserved.
#
# V1.4.0
#
# 2016.08.03
#
#
#
######################################################
# 1. 脚本集成到Xcode工程的Target
######################################################
#
# --- Copy the SCRIPT to the Run Script of Build Phases in the Xcode project ---
#
# #
BUGLY_APP_ID="" #必填 appId
# #
BUGLY_APP_KEY="" #必填 appKey
# #
BUNDLE_IDENTIFIER="" #必填 bundleId
# #
UPLOAD_DSYM_ONLY=1
#
# # 脚本默认配置的版本格式为CFBundleShortVersionString(CFBundleVersion), 如果你修改默认的版本格式, 请设置此变量, 如果不想修改, 请忽略此设置
# CUSTOMIZED_APP_VERSION=""
#
# # Debug模式编译是否上传,1=上传 0=不上传,默认不上传
# UPLOAD_DEBUG_SYMBOLS=0
#
# # 模拟器编译是否上传,1=上传 0=不上传,默认不上传
# UPLOAD_SIMULATOR_SYMBOLS=0
#
# #只有Archive操作时上传, 1=支持Archive上传 0=所有Release模式编译都上传
# UPLOAD_ARCHIVE_ONLY=1
#
# #
# source dSYMUpload.sh
#
# --- END OF SCRIPT ---
#
#
#
#
#######################################################
# 2. 脚本根据输入参数处理
#######################################################
#
# #命令行下输入应用基本信息, .dSYM文件的父目录路径, 输出文件目录即可
#
# sh dSYMUpload.sh
#
# #
#
# #注意:
# # 1. dSYMUpload.sh会调用buglySymboliOS.jar进行.dSYM解析,所以依赖Java运行时环境
# # 2. dSYMUpload.sh和buglySymboliOS.jar的文件路径需一致
#
#
#
# --- CONTENT OF SCRIPT ---
#
# Bugly服务域名
BUGLY_DSYM_UPLOAD_DOMAIN="api.bugly.qq.com"
# 注意jar工具的路径跟dSYMUpload.sh脚本路径一致, 请务必保证jar路径的正确性
BUGLY_SYMBOL_JAR_PATH="dsymtool/buglySymboliOS.jar"
# 查找添加到系统目录的jar工具
if [ ! -f "${BUGLY_SYMBOL_JAR_PATH}" ]; then
BUGLY_SYMBOL_JAR_PATH="$HOME/bin/buglySymboliOS.jar"
fi
# 打印错误信息
function exitWithMessage(){
echo "--------------------------------"
echo "${1}"
echo "--------------------------------"
exit ${2}
}
# 上传bSYMBOL文件
function dSYMUpload() {
P_APP_ID="$1"
P_APP_KEY="$2"
P_APP_BUNDLE_ID="$3"
P_APP_VERSION="$4"
P_BSYMBOL_ZIP_FILE="$5"
#
P_BSYMBOL_ZIP_FILE_NAME=${P_BSYMBOL_ZIP_FILE##*/}
P_BSYMBOL_ZIP_FILE_NAME=${P_BSYMBOL_ZIP_FILE_NAME//&/_}
P_BSYMBOL_ZIP_FILE_NAME="${P_BSYMBOL_ZIP_FILE_NAME// /_}"
DSYM_UPLOAD_URL="https://${BUGLY_DSYM_UPLOAD_DOMAIN}/openapi/file/upload/symbol?app_id=${P_APP_ID}&app_key=${P_APP_KEY}"
echo "dSYM upload url: ${DSYM_UPLOAD_URL}"
echo "-----------------------------"
STATUS=$(/usr/bin/curl -k "${DSYM_UPLOAD_URL}" --form "api_version=1" --form "app_id=${P_APP_ID}" --form "app_key=${P_APP_KEY}" --form "symbolType=2" --form "bundleId=${BUNDLE_IDENTIFIER}" --form "productVersion=${BUGLY_APP_VERSION}" --form "fileName=${P_BSYMBOL_ZIP_FILE_NAME}" --form "file=@${P_BSYMBOL_ZIP_FILE}" --verbose)
echo "-----------------------------"
UPLOAD_RESULT="FAILTURE"
echo "Bugly server response: ${STATUS}"
if [ ! "${STATUS}" ]; then
echo "Error: Failed to upload the zip archive file."
elif [[ "${STATUS}" == *"{\"reponseCode\":\"0\"}"* ]]; then
echo "Success to upload the dSYM for the app [${BUNDLE_IDENTIFIER} ${BUGLY_APP_VERSION}]"
UPLOAD_RESULT="SUCCESS"
else
echo "Error: Failed to upload the zip archive file to Bugly."
fi
#Remove temp dSYM archive
#echo "Remove temporary zip archive: ${DSYM_ZIP_FPATH}"
#/bin/rm -f "${DSYM_ZIP_FPATH}"
if [ "$?" -ne 0 ]; then
exitWithMessage "Error: Failed to remove temporary zip archive." 0
fi
echo "--------------------------------"
echo "${UPLOAD_RESULT} - dSYM upload complete."
if [[ "${UPLOAD_RESULT}" == "FAILTURE" ]]; then
echo "--------------------------------"
echo "Failed to upload the dSYM"
echo "Please check the script and try it again."
fi
}
# .dSYM解析为bSYMBOL文件
function dSYMParse() {
DSYM_FILE="$1"
DSYM_SYMBOL_FILE="$2"
echo "--------------------------------"
echo "Extract symbol info from .dSYM file. to ${DSYM_SYMBOL_FILE}"
(/usr/bin/java -Xms512m -Xmx1024m -Dfile.encoding=UTF8 -jar "${BUGLY_SYMBOL_JAR_PATH}" -i "${DSYM_FILE}" -o "${DSYM_SYMBOL_FILE}" ) || exitWithMessage "Error: Failed to extract symbols." 1
echo "--------------------------------"
}
# 执行
function run() {
CONFIG_BUGLY_APP_ID="$1"
CONFIG_BUGLY_APP_KEY="$2"
CONFIG_BUGLY_APP_BUNDLE_IDENTIFIER="$3"
CONFIG_BUGLY_APP_VERSION="$4"
CONFIG_DSYM_SOURCE_DIR="$5"
CONFIG_DSYM_DEST_DIR="$6"
CONFIG_UPLOAD_DSYM_ONLY="$7"
# 检查必须参数是否设置
if [ ! "${CONFIG_BUGLY_APP_ID}" ]; then
exitWithMessage "Error: Bugly App ID not defined. Please set 'BUGLY_APP_ID' " 0
fi
if [[ "${CONFIG_BUGLY_APP_ID}" == *"App ID"* ]]; then
exitWithMessage "Error: Bugly App ID not defined." 0
fi
if [ ! "${CONFIG_BUGLY_APP_KEY}" ]; then
exitWithMessage "Error: Bugly App Key not defined." 0
fi
if [ ! "${CONFIG_BUGLY_APP_BUNDLE_IDENTIFIER}" ]; then
exitWithMessage "Error: Bundle Identifier not defined." 0
fi
if [ ! "${CONFIG_BUGLY_APP_VERSION}" ]; then
exitWithMessage "Error: App Version not defined." 0
fi
if [ ! -e "${CONFIG_DSYM_SOURCE_DIR}" ]; then
exitWithMessage "Error: Invalid dir ${CONFIG_DSYM_SOURCE_DIR}" 0
fi
if [ ! "${CONFIG_DSYM_DEST_DIR}" ]; then
exitWithMessage "Error: Invalid dir ${CONFIG_DSYM_DEST_DIR}" 0
fi
if [ ! -e "${CONFIG_DSYM_DEST_DIR}" ]; then
mkdir ${CONFIG_DSYM_DEST_DIR}
fi
DSYM_FOLDER="${CONFIG_DSYM_SOURCE_DIR}"
IFS=$'\n'
echo "Scaning dSYM FOLDER: ${DSYM_FOLDER} ..."
RET="F"
#
for dsymFile in $(find "$DSYM_FOLDER" -name '*.dSYM'); do
RET="T"
echo "Found dSYM file: $dsymFile"
DSYM_FILE_NAME=${dsymFile##*/}
DSYM_SYMBOL_ZIP_FILE_NAME="${DSYM_FILE_NAME}.zip"
DSYM_SYMBOL_ZIP_FILE_NAME="${DSYM_SYMBOL_ZIP_FILE_NAME// /_}"
DSYM_SYMBOL_ZIP_FILE=${CONFIG_DSYM_DEST_DIR}/${DSYM_SYMBOL_ZIP_FILE_NAME}
if [ $CONFIG_UPLOAD_DSYM_ONLY -eq 1 ]; then
if [ -e $DSYM_SYMBOL_ZIP_FILE ]; then
rm -f $DSYM_SYMBOL_ZIP_FILE
fi
# 如果只上传dSYM,直接压缩dSYM目录
zip -r -j $DSYM_SYMBOL_ZIP_FILE $dsymFile -x *.plist
else
# 使用符号表工具来生成Symbol文件
dSYMParse $dsymFile $DSYM_SYMBOL_ZIP_FILE
fi
# 上传
dSYMUpload $CONFIG_BUGLY_APP_ID $CONFIG_BUGLY_APP_KEY $CONFIG_BUGLY_APP_BUNDLE_IDENTIFIER $CONFIG_BUGLY_APP_VERSION $DSYM_SYMBOL_ZIP_FILE
done
if [ $RET = "F" ]; then
exitWithMessage "No .dSYM found in ${DSYM_FOLDER}" 0
fi
}
# 在Xcode工程中执行
function runInXcode(){
echo "Uploading dSYM to Bugly in Xcode ..."
echo "Info.Plist : ${INFOPLIST_FILE}"
BUNDLE_VERSION=$(/usr/libexec/PlistBuddy -c 'Print CFBundleVersion' "${INFOPLIST_FILE}")
BUNDLE_SHORT_VERSION=$(/usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' "${INFOPLIST_FILE}")
# 组装Bugly默认识别的版本信息(格式为CFBundleShortVersionString(CFBundleVersion), 例如: 1.0(1))
if [ ! "${CUSTOMIZED_APP_VERSION}" ]; then
BUGLY_APP_VERSION="${BUNDLE_SHORT_VERSION}(${BUNDLE_VERSION})"
else
BUGLY_APP_VERSION="${CUSTOMIZED_APP_VERSION}"
fi
echo "--------------------------------"
echo "Prepare application information."
echo "--------------------------------"
echo "Product Name: ${PRODUCT_NAME}"
echo "Bundle Identifier: ${BUNDLE_IDENTIFIER}"
echo "Version: ${BUNDLE_SHORT_VERSION}"
echo "Build: ${BUNDLE_VERSION}"
echo "Bugly App ID: ${BUGLY_APP_ID}"
echo "Bugly App key: ${BUGLY_APP_KEY}"
echo "Bugly App Version: ${BUGLY_APP_VERSION}"
echo "--------------------------------"
echo "Check the arguments ..."
##检查模拟器编译是否允许上传符号
if [ "$EFFECTIVE_PLATFORM_NAME" == "-iphonesimulator" ]; then
if [ $UPLOAD_SIMULATOR_SYMBOLS -eq 0 ]; then
exitWithMessage "Warning: Build for simulator and skipping to upload. \nYou can modify 'UPLOAD_SIMULATOR_SYMBOLS' to 1 in the script." 0
fi
fi
##检查是否是Release模式编译
if [ "${CONFIGURATION=}" == "Debug" ]; then
if [ $UPLOAD_DEBUG_SYMBOLS -eq 0 ]; then
exitWithMessage "Warning: Build for debug mode and skipping to upload. \nYou can modify 'UPLOAD_DEBUG_SYMBOLS' to 1 in the script." 0
fi
fi
##检查是否Archive操作
if [ $UPLOAD_ARCHIVE_ONLY -eq 1 ]; then
if [[ "$TARGET_BUILD_DIR" == *"/Archive"* ]]; then
echo "Archive the package"
else
exitWithMessage "Warning: Build for NOT Archive mode and skipping to upload. \nYou can modify 'UPLOAD_ARCHIVE_ONLY' to 0 in the script." 0
fi
fi
#
run ${BUGLY_APP_ID} ${BUGLY_APP_KEY} ${BUNDLE_IDENTIFIER} ${BUGLY_APP_VERSION} ${DWARF_DSYM_FOLDER_PATH} ${BUILD_DIR}/BuglySymbolTemp ${UPLOAD_DSYM_ONLY}
}
# 根据Xcode的环境变量判断是否处于Xcode环境
INFO_PLIST_FILE="${INFOPLIST_FILE}"
BuildInXcode="F"
if [ -f "${INFO_PLIST_FILE}" ]; then
BuildInXcode="T"
fi
if [ $BuildInXcode = "T" ]; then
runInXcode
else
echo "\nUsage: dSYMUpload.sh [upload_dsym_only]\n"
# 你可以在此处直接设置BuglyAppID和BuglyAppKey,排除不常变参数的输入
BUGLY_APP_ID="$1"
BUGLY_APP_KEY="$2"
BUNDLE_IDENTIFIER="$3"
BUGLY_APP_VERSION="$4"
DWARF_DSYM_FOLDER_PATH="$5"
SYMBOL_OUTPUT_PATH="$6"
UPLOAD_DSYM_ONLY=$7
run ${BUGLY_APP_ID} ${BUGLY_APP_KEY} ${BUNDLE_IDENTIFIER} ${BUGLY_APP_VERSION} ${DWARF_DSYM_FOLDER_PATH} ${SYMBOL_OUTPUT_PATH} ${UPLOAD_DSYM_ONLY}
fi
ERROR ITMS-90087解决脚本
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
找到view所在controller
func responderViewController() -> UIViewController {
var responder: UIResponder! = nil
var next = self.superview
while next != nil {
responder = next?.next
if (responder!.isKind(of: UIViewController.self)){
return (responder as! UIViewController)
}
next = next?.superview
}
return (responder as! UIViewController)
}
强制转屏
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
UIApplication.shared.statusBarOrientation = .landscapeRight
}
判断系统SDK是否支持iOS10
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import
@interface AppDelegate()
@end
#endif
判断设备为手机还是iPad
if UI_USER_INTERFACE_IDIOM() == .Phone {
}
/*
case Unspecified
@available(iOS 3.2, *)
case Phone // iPhone and iPod touch style UI
@available(iOS 3.2, *)
case Pad // iPad style UI
@available(iOS 9.0, *)
case TV // Apple TV style UI
@available(iOS 9.0, *)
case CarPlay // CarPlay style UI
*/
UISegmentedControl样式自定义
let sc: UISegmentedControl = UISegmentedControl(items: ["111","222"])
sc.layer.borderWidth = 0
sc.layer.borderColor = UIColor.clearColor().CGColor
sc.layer.cornerRadius = 0
sc.selectedSegmentIndex = 0
sc.setTitle("问答讨论", forSegmentAtIndex: 0)
sc.setTitle("学习资料", forSegmentAtIndex: 1)
sc.setBackgroundImage(UIImage(), forState: .Normal, barMetrics: .Default)
sc.setBackgroundImage(UIImage(), forState: .Selected, barMetrics: .Default)
sc.setBackgroundImage(UIImage(), forState: .Highlighted, barMetrics: .Default)
sc.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor(hex: 0xa8a8a8)!, NSFontAttributeName: UIFont.systemFontOfSize(16)], forState: .Normal)
sc.setTitleTextAttributes([NSForegroundColorAttributeName: CommenColor.Blue, NSFontAttributeName: UIFont.systemFontOfSize(16)], forState: .Selected)
sc.setDividerImage(UIImage(named: "line_vertical"), forLeftSegmentState: .Normal, rightSegmentState: .Normal, barMetrics: .Default)
Swift懒加载
private lazy var tableView: UITableView = {
let tb: UITableView = UITableView(frame: CGRectZero, style: .Plain)
tb.delegate = self
tb.dataSource = self
tb.registerClass(LiveChatViewCell.self, forCellReuseIdentifier: "LiveChatViewCell")
tb.separatorStyle = .None
tb.tableFooterView = UIView()
tb.estimatedRowHeight = 60
tb.rowHeight = UITableViewAutomaticDimension
return tb
}()
UIView布局动画
// 告诉self.view约束需要更新
view.needsUpdateConstraints()
// 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
view.updateConstraintsIfNeeded()
// 更新动画
UIView.animateWithDuration(duration) {
self.view.layoutIfNeeded()
}
UILabel富文本
let attach = NSTextAttachment()
attach.image = UIImage(named: "icon")
attach.bounds = CGRectMake(0, -2, 32, 18)
let attr = NSMutableAttributedString(string: " 标题")
attr.insertAttributedString(NSAttributedString(attachment: attach), atIndex: 0)
UILabel/UITextView加载html文本
NSString * htmlString = @"xxxx";
NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUnicodeStringEncoding]
options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
UILabel * myLabel = [[UILabel alloc] initWithFrame:self.view.bounds];
myLabel.attributedText = attrStr;
准确实时判断UIPanGesture的滑动方向
方法1:垂直/水平方向
// 根据上次和本次移动的位置,算出一个速率的point
let velocityPoint = pan.velocity(in: self)
switch pan.state {
case UIGestureRecognizerState.began:
// 使用绝对值来判断移动的方向
let x = fabs(velocityPoint.x)
let y = fabs(velocityPoint.y)
if x > y {
self.panDirection = .horizontal
} else {
self.panDirection =.vertical
}
方法2:向左/右
//滑动手势方法
-(void)actionOfPan: (UIPanGestureRecognizer*)pan
{
CGFloat location = [pan locationInView:pan.view];
static CGFloat lastX = 0; //静态局部变量,记录上一次位置
switch (pan.state)
{
case UIGestureRecognizerStateBegan:
{
lastX = location.x; //开始时上一次滑动位置
}
break;
case UIGestureRecognizerStateChanged:
{
CGFloat delta = location.x - lastX; //计算差值
if (delta == 0) {
return;
}
if (delta < 0) {
NSLog(@"<----"); //向左
}
else{
NSLog(@"---->"); //向右
}
lastX = location.x; //滑动时重新赋值上一次记录
}
break;
case UIGestureRecognizerStateEnded:
{
lastX = 0; //重置
}
break;
default:
{
}
break;
}
}
NSString中文编码
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"test.txt" ofType:nil]];
NSStringEncoding encode = CFStringConvertEncodingToNSStringEncoding (kCFStringEncodingGB_18030_2000);
NSString *str = [[NSString alloc] initWithData:data encoding:encode];
点击缩放跳转动画
// point缩放动画
-(void)pagePositionScaleAnimationWithCell:(UICollectionViewCell*)cell view:(UIView*)view{
view.center = cell.center;
view.transform = CGAffineTransformMakeScale(cell.frame.size.width/view.frame.size.width, cell.frame.size.height/view.frame.size.height);
CGFloat x = cell.center.x;
CGFloat y = cell.frame.origin.y - self.collectionView.contentOffset.y + cell.frame.size.height/2 + 64;
view.center = CGPointMake(x, y);
// view.alpha = 0;
[UIView animateWithDuration:0.3 animations:^{
view.transform = CGAffineTransformMakeScale(1, 1);
view.center = self.view.center;
// view.alpha = 1;
}];
}
// 水波动画
-(void)pageRippleAnimation:(UIView*)view{
CATransition *transition = [CATransition animation];
transition.duration = 0.8;
transition.type = @"rippleEffect";
// rippleEffect | cube | pageCurl | pageUnCurl | suckEffect | oglFlip | moveIn | fade | reveal
[view.layer addAnimation:transition forKey:nil];
}
// center缩放动画
-(void)pageScaleAnimation:(UIView*)view{
view.frame = self.view.frame;
view.transform = CGAffineTransformMakeScale(0.1, 0.1);
view.alpha = 0;
[UIView animateWithDuration:0.3 animations:^{
view.transform = CGAffineTransformMakeScale(1, 1);
view.alpha = 1;
}];
}
KVO实现数组个数改变的监听
//1. 定义数组
@property(nonatomic,strong)NSMutableArray *array;
//2. add observer --- @count为数组的属性
[self addObserver:self forKeyPath:@"array.@count"
options:NSKeyValueObservingOptionNew context:nil];
//3. 改变数组的值,但注意不能用[array addObject: ] 或 [array insert]、removeObject等去改变数组的元素
//而是要改用:
[[self mutableArrayValueForKey:@"array"] addObject: xxx]; // KVC的方式获取数组
//4. 监听处理
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object change:(NSDictionary *)change
context:(void *)context{
if ([keyPath isEqualToString:@"pathArray.@count"]) {
NSInteger count = [change[NSKeyValueChangeNewKey] integerValue];
// do something...
}
}
图片裁剪
// 从view渲染得到图片
-(UIImage *)renderImageFromCurrentView{
// 渲染
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
// 裁剪 - !!!rect记得 x 缩放比
-(UIImage *)clipImageFromOriginalImage: (UIImage*)orgImage
inRect: (CGRect)rect{
rect.origin.x *= orgImage.scale;
rect.origin.y *= orgImage.scale;
rect.size.width *= orgImage.scale;
rect.size.height *= orgImage.scale;
UIImage *image = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(orgImage.CGImage, rect)];
return image;
}
计算出绘图轮廓矩形
-(CGRect)getOutlineRectOfCurrentPaths{ //轮廓矩形
CGFloat xmin = CGRectGetMaxX(self.bounds);
CGFloat ymin = CGRectGetMaxY(self.bounds);
CGFloat xmax = 0;
CGFloat ymax = 0;
for (UIBezierPath *path in self.pathArray)
{
NSMutableArray *points = [NSMutableArray array];
CGPathApply(path.CGPath, (__bridge void *)points, getPointsFromBezier);
for (int i=0; i xmax) {
xmax = x;
}
if (y < ymin) {
ymin = y;
}
if (y > ymax) {
ymax = y;
}
}
}
CGRect rect = CGRectMake(xmin, ymin, xmax-xmin, ymax-ymin);
return rect;
}
获取UIBezierPath上的所有点
// 用法:
NSMutableArray *keyPoints = [NSMutableArray array];
CGPathApply(yourPath.CGPath, (__bridge void *)keyPoints, getPointsFromBezier);
// 现成方法
void getPointsFromBezier (void *info, const CGPathElement *element) {
NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;
CGPoint *points = element->points;
CGPathElementType type = element->type;
switch(type) {
case kCGPathElementMoveToPoint: // contains 1 point
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
break;
case kCGPathElementAddLineToPoint: // contains 1 point
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
break;
case kCGPathElementAddQuadCurveToPoint: // contains 2 points
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]];
break;
case kCGPathElementAddCurveToPoint: // contains 3 points
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[2]]];
break;
case kCGPathElementCloseSubpath: // contains no point
break;
}
}
半透明present出来的viewcontroller
MyViewController *vc = [MyViewController new];
vc.view.backgroundColor = [UIColor clearColor];
vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
//尝试了这种模式下切换比较自然且会起到作用
隐藏tableview多余的分割线
//1 以前我是将left的margin设置得很大,目的是‘挤跑’多余的分割线
tableView.separatorInset = UIEdgeInsetsMake(0, 100000, 0, 0);
// 然后在cell中,又设置回来,比如
cell.separatorInset = UIEdgeInsetsMake(0, 10, 0, 0);
//2 后来发现有人这样做:【推荐】
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
数组元素排序,NSString比较
需求:顺序/倒序 排序数组中的name属性
NSArray *array = @[
@{
@"name": @"02. 资源1"
},
@{
@"name": @"03-1. 资源2"
},
@{
@"name": @"02-1. 资源3"
}
];
-(NSArray*)sortedArrayWithArray: (NSArray*)array{
NSComparator sort = ^(NSDictionary *obj1, NSDictionary *obj2){
NSRange range = NSMakeRange(0, 6); //03-00 < 03-01
// 顺序
return [obj1[@"name"] compare:obj2[@"name"] options:NSNumericSearch range:range];
// 倒序
// return [obj2[@"name"] compare:obj1[@"name"] options:NSNumericSearch range:range];
};
NSArray *result = [array sortedArrayUsingComparator:sort];
NSLog(@"字符串数组排序结果%@",result);
return result;
}
输出:[
@{
@"name": @"02. 资源1"
},
@{
@"name": @"02-1. 资源2"
},
@{
@"name": @"03-1. 资源3"
}
];
NSString-boundingRect-较为精确
//包含换行、回车、空格等都会计算高度
NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:16]};
CGSize size = [str boundingRectWithSize:CGSizeMake(width, 0)
options: NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:attributes context:nil].size;
swift将图片重新渲染成新的颜色
extension UIView类的类方法
class func renderWithNewColor(imageName:String, color: UIColor) -> UIImage{
let image = UIImage(named: imageName)!
// @2x的图建议*2 不然会虚 一般的.png图就不用*1
let size = CGSizeMake(image.size.width * 2, image.size.height * 2)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, .Normal);
let rect = CGRectMake(0, 0, size.width, size.height);
CGContextClipToMask(context, rect, image.CGImage);
color.setFill()
CGContextFillRect(context, rect);
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
OC将UIView转UIImage
-(UIImage*)viewRenderToImage: (UIView*)view{
CGSize size = view.bounds.size;
//第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了
UIGraphicsBeginImageContextWithOptions(size, false, [UIScreen mainScreen].scale);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
OC单例
+(Manager*)sharedManager{
static Manager* manager = nil;
static dispatch_once_t token;
dispatch_once(&token, ^{
manager = [Manager new];
});
return manager;
}
屏幕旋转 - 切记项目支持全屏时,该方法才起作用
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotate{
return true;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
选中/取消选中动画
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
cell复用
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
swift协议
@objc
protocol XXXDelegate :NSObjectProtocol {
// 方法
optional func xxx()
}
// 代理
weak var delegate : XXXDelegate?
NavBar全透明
nav.navigationBar.setBackgroundImage(UIImage(),forBarMetrics: UIBarMetrics.Default)
nav.navigationBar.shadowImage = UIImage()
nav.navigationBar.translucent = true
TabBar
// 添加子控件
private func addViewController(childController: UIViewController, title: String) {
let nav = NavgationViewController(rootViewController: childController)
addChildViewController(nav)
childController.tabBarItem.title = title
childController.tabBarItem.image = UIImage(named: "tb_\(childViewControllers.count - 1)")
childController.tabBarItem.selectedImage = UIImage(named: "tb_\(childViewControllers.count - 1)" + "_selected")
// 设置tabBarItem的tag, 方便判断点击
childController.tabBarItem.tag = childViewControllers.count-1
}
// 点击profile的时候.判断是否登录. 如果没有登录, 需要跳转到登录界面, 反之则跳转到个人界面
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool
{
return true
}
swift-单例
// 一句话实现单例(swift2.0)
static let sharedInstance = LoginHelper()
private override init() {} // 防止使用()初始化
swift-UIView自定义初始化方法
convenience init(iconName: String, placeHolder: String, isLocation: Bool, isPhone: Bool, isSafe: Bool)
{
self.init(frame: CGRectZero)
// 其他初始化设置
}