iOS雜碎念

座右銘.jpg
TableView長截圖

UIImage  *image = nil;
// 下面的方法危纫,第一個參數(shù)表示區(qū)域大小。第二個參數(shù)表示是否是非透明的拒垃。如果需要顯示半透明效果冲甘,需要傳NO碗硬,否則傳YES吝秕。第三個參數(shù)就是屏幕密度了洲劣,調(diào)整清晰度搏明。
UIGraphicsBeginImageContextWithOptions(self.tableView.contentSize, YES, [UIScreen mainScreen].scale);
CGPoint savedContentOffset = self.tableView.contentOffset;
CGRect savedFrame = self.tableView.frame;
self.tableView.contentOffset = CGPointZero;
self.tableView.frame = CGRectMake(0, 0, self.tableView.contentSize.width, self.tableView.contentSize.height);
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
self.tableView.contentOffset = savedContentOffset;
self.tableView.frame = savedFrame;
UIGraphicsEndImageContext();
UIColor添加透明度
UIColor *color = [[YMSkinHelper single] skinColor];
CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
color = [UIColor colorWithRed:red green:green blue:blue alpha:0.3];
關(guān)于setObjectsetValue方法的區(qū)別
NSString *test = nil;
    
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:@"1" forKey:@"key1"];
//[dic setObject:@"1" forKey:test];//key不能為nil,崩潰.
//[dic setObject:test forKey:@"key2"];//object不能為nil,崩潰.
    
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:@"1" forKey:@"key1"];
//[dict setValue:@"1" forKey:test];//key不能為nil,崩潰.
[dict setValue:test forKey:@"key2"];//value可以為nil,不會崩潰,但是會調(diào)用removeObject:forKey方法導(dǎo)致key2鍵值對不存在.
    
NSLog(@"%@  %@", dic, dict);

iOS開發(fā) 調(diào)用手機微微震動效果
1. 導(dǎo)入框架
#import <AudioToolbox/AudioToolbox.h>

2.調(diào)用震動方法,一句代碼解決
// 普通短震,3D Touch 中 Pop 震動反饋
AudioServicesPlaySystemSound(1520);
// 普通短震闪檬,3D Touch 中 Peek 震動反饋
AudioServicesPlaySystemSound(1519);
// 連續(xù)三次短震
AudioServicesPlaySystemSound(1521);
UIView設(shè)置陰影時需要注意
// 投影
// _progressView.layer.masksToBounds = YES;
_progressView.layer.cornerRadius = 4;
 _progressView.backgroundColor = RGB(28, 151, 255);

_progressView.layer.shadowRadius = 5;
_progressView.layer.shadowOpacity = 0.75;
_progressView.layer.shadowOffset = CGSizeMake(0, 3);
_progressView.layer.shadowColor = RGB(52, 121, 249).CGColor;

在通過這樣的方式設(shè)置陰影時星著,必須把父視圖的masksToBounds屬性關(guān)掉,因為陰影設(shè)置的方式就是加offset給超出視圖部分設(shè)置顏色來實現(xiàn)的粗悯,一旦不讓子視圖超出虚循,陰影也就看不出了。查看更多解決方案...

iOS UILabel 圓角與陰影共存
_textLabel.layer.backgroundColor = RGB(8, 92, 115).CGColor;
//_textLabel.layer.masksToBounds = YES;
_textLabel.layer.cornerRadius = _textLabel.height/2;
_textLabel.layer.shadowColor = RGB(8, 92, 115).CGColor;
_textLabel.layer.shadowOffset = CGSizeMake(0, 5);
 _textLabel.layer.shadowOpacity = 5;
iOS11 Xcode9 [_tableView reloadData] 刷新tableView跳動問題解決辦法
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;

更多關(guān)于 iOS11的適配問題,詳見10分鐘適配 iOS 11 & iPhone X

iOS 10.3 UILabel 中劃線失效
// iOS10.3系統(tǒng)的一個Bug样傍,在UILable中含有中文時横缔,中劃線會失效
[attStr addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:defaultRange]; 

// 解決辦法
[attStr addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:defaultRange];
[attStr addAttribute:NSBaselineOffsetAttributeName value:@(NSUnderlineStyleSingle) range:defaultRange];
Xcode編譯報 duplicate symbols for architecture arm64
ld: 10 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

原因

    1. 查看自己項目中是否有重復(fù)命名的文件
      (一般就是這個問題,如果項目中排查后衫哥,沒有發(fā)現(xiàn)茎刚,就該項目所在的文件是否有重復(fù)命名的文件,刪除一個就可以了撤逢,排查的目標(biāo)一般都在報錯前面列舉出來了)
    1. 再查看是否在編輯 #improt 頭文件時候膛锭,不小心把 .h 誤寫成 .m
FMDatabaseQueue lead to a deadlock
Assertion failed: (currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"), 
function -[FMDatabaseQueue inDatabase:], file /Users/HaobingW/Desktop/Project/OpenSource/YMFMDB/fmdb/FMDatabaseQueue.m, line 178.

運行app,發(fā)現(xiàn)在“assert(currentSyncQueue != self && “inDatabase: was called reentrantly on the same queue, which would lead to a deadlock”);”這句crash掉了蚊荣。
然后就去先看一下大意:
斷言失敗(Assertion 單元測試的時候會經(jīng)常碰到)初狰,inDatabase 在相同的queue隊列中被重復(fù)調(diào)用,引發(fā)死鎖互例。

原因
在使用時奢入,如果在queue里面的block執(zhí)行過程中,又調(diào)用了 indatabase方法媳叨,則會檢查 是不是同一個queue腥光,如果是同一個queue會死鎖;原因很簡單:
隊列里面 放了一個block糊秆,該block又在 本隊列 后面放了一個 block武福;
從而:前一個block 里面 調(diào)用了 后一個block,必須等后一個block執(zhí)行完成了扩然,
前一個block才會 出隊列艘儒;
而后一個block想要執(zhí)行,則又必須先等 前一個block出隊列;
因此 死鎖=缯觥>踉觥!翻斟!

解決方法
在indatabase的block中逾礁,不要再調(diào)用indatabase方法。這個細心一下访惜,多數(shù)時候很容易發(fā)現(xiàn)嘹履。
可是有時候因代碼封裝等問題,大家可能很難發(fā)現(xiàn)問題所在债热。那么就來個暴力斷點吧砾嫉。在每一個使用indatabase的地方都 NSLog(或者print)一下一個編號。 然后crash的時候窒篱,看一下最后是哪兩個相互發(fā)生的影響造成的死鎖焕刮。

tabBar 圖片顏色顯示效果與UI切圖不一致
// 創(chuàng)建 tabBar
UITabBarItem *homeBar = [[UITabBarItem alloc] initWithTitle:@"home" 
image:[[UIImage imageNamed:@"tab_home_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] 
selectedImage:[[UIImage imageNamed:@"tab_home_light"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];

為了防止系統(tǒng)渲染,必須以UIImageRenderingModeAlwaysOriginal提供圖片墙杯。若不以這種形式配并,那么提供的圖片顯示時會發(fā)生渲染錯誤的問題。

在IOS7中增加創(chuàng)建UITabBarItem的方法的同時新增了 UIImageRenderingMode屬性

typedef NS_ENUM(NSInteger, UIImageRenderingMode) {
    UIImageRenderingModeAutomatic,          // Use the default rendering mode for the context where the image is used
    UIImageRenderingModeAlwaysOriginal,     // Always draw the original image, without treating it as a template
    UIImageRenderingModeAlwaysTemplate,     // Always draw the image as a template image, ignoring its color information } NS_ENUM_AVAILABLE_IOS(7_0);
}
  • UIImageRenderingModeAutomatic //根據(jù)圖片的使用環(huán)境和所處的繪圖上下文自動調(diào)整渲染模式高镐。
  • UIImageRenderingModeAlwaysOriginal //始終繪制圖片原始狀態(tài)溉旋,不使用Tint Color。
  • UIImageRenderingModeAlwaysTemplate //始終根據(jù)Tint Color繪制圖片嫉髓,忽略圖片的顏色信息观腊。
使用Copy崩潰的問題

奔潰原因

解決方法,實現(xiàn)協(xié)議及方法
@interface CustomClass : NSObject <NSCopying,NSMutableCopying>

-(id)copyWithZone:(NSZone *)zone {

    CustomClass *newClass = [[CustomClass alloc]init];
    newClass.testString = self.testString;
    return newClass;
}

側(cè)滑手勢禁用與恢復(fù)
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // 禁用側(cè)滑返回
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // 恢復(fù)側(cè)滑返回
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    }
}
locationInView 與 translationInView 的區(qū)別

locationInView: 獲取到的是手指點擊屏幕實時的坐標(biāo)點
translationInView: 獲取到的是手指移動后相對于手勢起始點的偏移量

CGPoint point = [gesture locationInView:self.view];
CGPoint transPoint = [gesture translationInView:self.view];
NSLog(@"\n%f++++%f\n %f-----%f",point.x,point.y,transPoint.x,transPoint.y);
動畫的暫停和恢復(fù)
//暫停動畫.保存當(dāng)前位置和時間
- (void)pauseSynAnimation {
    CFTimeInterval pausedTime = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    self.imageView.layer.timeOffset = pausedTime;
}

//恢復(fù)動畫
- (void)resumeSynLayer {
    [self.imageView.layer removeAllAnimations];
    animation.timeOffset = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil] - self.imageView.layer.timeOffset;
    [self.imageView.layer addAnimation:animation forKey:nil];
}

注意: animation 為動畫對象,是一個全局變量.
UILabel豎直方向排列
UILabel不能設(shè)置方向豎直方向排列,但可以通過sizeToFit改變frame來實現(xiàn):
CGRect labelFrame =CGRectMake(20,20,30,150);
UILabel*myLabel= [[UILabel alloc]initWithFrame:labelFrame];
myLabel.backgroundColor=[UIColor orangeColor];
NSString*text =@"今天是個好日子啊今天是個好日子啊今天是個好日子啊";
myLabel.text=text;
myLabel.numberOfLines=0;
[myLabelsizeToFit];
[self.view addSubview:myLabel];

[引自](http://www.reibang.com/p/f8405416fc9d)
ScrollView代理方法
// 開始拖拽時調(diào)用
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; 

// 結(jié)束拖拽(手指松開)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 

 // 結(jié)束減速岩喷,手指操作恕沫,停止?jié)L動
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

// 結(jié)束滾動動畫监憎,非手指操作纱意,停止?jié)L動
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView; 

// 正在滾動
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; 
IOS 關(guān)于取消延遲執(zhí)行函數(shù)
// 延遲執(zhí)行函數(shù)
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;  
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;  

// 取消延遲執(zhí)行函數(shù)
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;  
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;

關(guān)于取消延遲執(zhí)行函數(shù),如果是帶參數(shù)的,那么取消時參數(shù)也要保持一致,否則將會取消失敗.
// 例如:
// 30秒后執(zhí)行延遲函數(shù)
[self performSelector:@selector(SyncTimeOut) withObject:nil afterDelay:30.f];

// 取消執(zhí)行延遲函數(shù)
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(SyncTimeOut) object:nil];
字符串的處理
// 去除字符串中被特殊字符括住的字符
- (NSString *)handleStringWithString:(NSString *)str {
    
    NSMutableString * muStr = [NSMutableString stringWithString:str];
    while (1) {
        NSRange range = [muStr rangeOfString:@"<"];
        NSRange range1 = [muStr rangeOfString:@">"];
        if (range.location != NSNotFound) {
            NSInteger loc = range.location;
            NSInteger len = range1.location - range.location;
            [muStr deleteCharactersInRange:NSMakeRange(loc, len + 1)];
        }else{
            break;
        }
    }
    return muStr;
}

// test
NSString *str = @"abcdef<asljsf>fed<123>cba<hhhhhhh>";
NSString *result = [self handleStringWithString:str];
NSLog(@"%@" , result); //abcdeffedcba
??/// 將數(shù)組轉(zhuǎn)化為json.
+ (NSString *)jsonFromArray:(NSArray *)array
{
    NSData *data=[NSJSONSerialization dataWithJSONObject:array
                                                 options:NSJSONWritingPrettyPrinted
                                                   error:nil];
    if (data == nil) {
        return nil;
    }
    NSString *str=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    return str;
}
自定義View手勢解決和tableview點擊沖突
// 1.添加并設(shè)置代理  UIGestureRecognizerDelegate
// 2.實現(xiàn)代理方法,加以判斷
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    //判斷如果點擊的是tableView的cell,就把手勢給取消了
    if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) {
        //取消手勢
        return NO;
    }
    //否則手勢存在
    return YES;
}
Center
CGRect rect = self.bounds;
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
scrollView三個基本屬性鲸阔;

contentSize
蘋果官方文檔的解釋是:The size of the content view. 所以很好理解偷霉,contentSize也就是scrollView可滾動的區(qū)域;
contentOffset
蘋果官方文檔的解釋是:The point at which the origin of the content view is offset from the origin of the scroll view. 注意褐筛,這里標(biāo)注的是 point 类少,是當(dāng)前顯示的區(qū)域的 origin 相對于整個scrollView的origin的位置;
contentInset
蘋果官方文檔的解釋是:The distance that the content view is inset from the enclosing scroll view.注意渔扎,這里說得是distance硫狞,四個值分別是上下左右

為 View 添加背景圖
NSString *path = [[NSBundle mainBundle]pathForResource:@"ImageName"ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
self.layer.contents = (id)image.CGImage;
局部cell更新
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];

傳入?yún)?shù)就是要刷新的cell所在的indexPath組成的數(shù)組。
但,reloadItemsAtIndexPath默認會有一個動畫的過程残吩,cell內(nèi)容更新的瞬間會出現(xiàn)原內(nèi)容與新內(nèi)容重疊的情況财忽。那么使用如下方式取消該動畫即可:

[UIView performWithoutAnimation:^{
    [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
}];

iOS --- UICollectionView中使用reloadItemsAtIndexPaths進行局部cell更新

runtime 獲取某個類的方法名
// 以 NSArray 為例
unsigned int count = 0;
Method *methods = class_copyMethodList([NSArray class], &count);
for (int i = 0; i < count; i++) {
     Method method = methods[i];
     SEL methodSel = method_getName(method);
     NSLog(@"%@", NSStringFromSelector(methodSel));
}

為 CollectionView 添加類似 tableView 的點擊改變背景色的效果.

思路:可以通過在 cell 的 contentView 上添加一個 button , 在 button 的點擊事件中實現(xiàn)背景顏色的改變等.至于 push 等操作則可以通過為 cell 添加代理實現(xiàn).如下:

// 1.懶加載添加 touchBtn
- (UIButton *)touchBtn {
    if (!_touchBtn) {
        _touchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        _touchBtn.frame = CGRectMake(3.f, 3.f, _imageView.width-6.f, _imageView.height-6.f);
        [_touchBtn addTarget:self action:@selector(onTouchCell) forControlEvents:UIControlEventTouchUpInside];
    }
    return _touchBtn;
}

// 2.將其添加到自定義 cell 的contentView
[self.contentView addSubview:self.touchBtn];

// 3.實現(xiàn)button 的點擊事件
- (void)onTouchCell {
    _touchBtn.alpha = 0.5f;
    _touchBtn.backgroundColor = [UIColor blackColor];
    __block typeof(self) weakSelf = self;
    [UIView animateWithDuration: 0.4f animations:^{
        weakSelf.touchBtn.backgroundColor = [UIColor clearColor];
    }];
    // 在 button 的點擊方法中通過為 cell 添加代理,傳入 indexPath 實現(xiàn) cell 的 push 等操作. 
    [weakSelf.cellDelegate onTouchCell:weakSelf.indexPath];
}

// 4.為自定義的 cell 添加代理
@protocol YMSCCollectionCellDelegate <NSObject>
- (void)onTouchCell: (NSIndexPath *)indexPath;
@end

@property(nonatomic, weak) id<YMSCCollectionCellDelegate> cellDelegate;

// 5.回到 collectionViewController 中遵循 YMSCCollectionCellDelegate ,在返回 cell 的方法中為 cell 添加代理,并傳入 indexPath.
@interface YMCommunityFindView ()<UICollectionViewDelegate, UICollectionViewDataSource, YMSCCollectionCellDelegate>

collectionCell.cellDelegate = self;
collectionCell.indexPath = indexPath;

// 6.實現(xiàn)協(xié)議中的方法
#pragma mark - YMSCCollectionCellDelegate
- (void)onTouchCell:(NSIndexPath *)indexPath {
   //  to do push...
}

當(dāng)然,除了通過添加 button 外,還可以通過為 collectionCell 上添加單擊手勢,push 的實現(xiàn)依然可以通過設(shè)置代理實現(xiàn).
__block typeof(self) weakSelf = self;
[self.contentView addTapGesture:^{
    [UIView animateWithDuration:0.1f animations:^{
        weakSelf.orderDetail.backgroundColor = RGBA(0, 0, 0, 0.1);
    } completion:^(BOOL finished) {
        weakSelf.orderDetail.backgroundColor = [UIColor whiteColor];
        [weakSelf.cellDelegate onTouchCell:weakSelf.indexPath];
    }];
}];

iOS關(guān)于BOOL 值的處理(一次很逗比的 bug 事件).

問題描述:服務(wù)端定義了一個 bool類型的變量返回true / false ,通過網(wǎng)頁 json 解析也可以明確知道它是一個 bool 類型的值.

"cornerMark": 0, 
"friendshipType": 0, 
"id": 1040410, 
"isApply": 0, 
"isZan": false, //服務(wù)端定義的 bool 類型變量
"publisher": 103095882, 
"publisherName": "Harryoil", 

然后客戶端通過網(wǎng)絡(luò)請求后拿不到值,Xcode debug 顯示值為 no summary.此外, 更奇怪的是,所有服務(wù)端定義的 bool 類型的值,客戶端都顯示為no summary

no summary

解決過程:關(guān)于此類問題,我在 CocoaChina 上面也遇到了同樣的疑惑,具體可參考這里 ,然而并沒有得到解決辦法.幾經(jīng)折騰,依然無法拿到正常的 bool 值, 這個時候我們開始懷疑是不是自己封裝的請求類出了問題,于是開始入坑查找,結(jié)局很明顯,未果.一次偶然的機會,在與后端溝通的過程中了解到,其實是傳參時將"uid" 傳成了"userId"(這兩個字段本質(zhì)上都是用戶的 ID, 只是服務(wù)端在改版的過程中換了個字段名而已),導(dǎo)致取不到任何用戶相關(guān)的一些信息(比如點贊,評論信息等),總結(jié): 溝通為先,效率至上.

iOS 崩潰日志分析

應(yīng)用程序通過集成友盟的bug收集SDK, 待 App上線后,如果發(fā)生崩潰,崩潰日志將被保存下來,并上報到友盟后臺,通過登錄后臺就能夠很清楚地知道奔潰日志記錄的錯誤信息. 要分析奔潰日志,首先需要我們保留發(fā)布時編譯出來的.xcarchive文件,該文件中保存了.dSYM文件,通常我們可以通過打開XCode->Window->Organizer在編譯成功的文件上右鍵,就能打開泣侮。
通過分析.dSYM文件定位崩潰位置的原理:Xcode 編譯項目完成后,會生成一份同名的.dSYM文件,這個文件是保存了16進制函數(shù)地址映射信息的中轉(zhuǎn)文件. 當(dāng)應(yīng)用程序 crash 時, iOS 設(shè)備會通過 crash 日志文件保存我們每個應(yīng)用程序出錯函數(shù)的內(nèi)存地址,通過這個函數(shù)地址去查詢 dSYM 文件中對應(yīng)的函數(shù)名和文件名就能精確定位到發(fā)生奔潰的地方.

什么是 dSYM 文件 ?
Xcode編譯項目后即彪,我們會看到一個同名的 dSYM 文件,dSYM 是保存 16 進制函數(shù)地址映射信息的中轉(zhuǎn)文件活尊,我們調(diào)試的 symbols 都會包含在這個文件中隶校,并且每次編譯項目的時候都會生成一個新的 dSYM 文件,對于每一個發(fā)布版本我們都很有必要保存對應(yīng)的 Archives 文件.

**dSYM 文件有什么作用 ? **
當(dāng)我們軟件 release 模式打包或上線后蛹锰,不會像我們在 Xcode 中那樣直觀的看到用崩潰的錯誤深胳,這個時候我們就需要分析 crash report 文件了,iOS 設(shè)備中會有日志文件保存我們每個應(yīng)用出錯的函數(shù)內(nèi)存地址铜犬,通過 Xcode 的 Organizer 可以將 iOS 設(shè)備中的 DeviceLog 導(dǎo)出成 crash 文件稠屠,這個時候我們就可以通過出錯的函數(shù)地址去查詢 dSYM 文件中程序?qū)?yīng)的函數(shù)名和文件名。大前提是我們需要有軟件版本對應(yīng)的 dSYM 文件翎苫,這也是為什么我們很有必要保存每個發(fā)布版本的 Archives 文件了权埠。
引自dSYM文件分析工具的開發(fā)者answerhuang

附:
手動解析CrashLog之原理篇
手動解析CrashLog之----方法篇
dSYM文件分析工具下載地址 密碼: vtce

iOS8下發(fā)送通知NSNotification崩潰

StoreAllOrderTableView類中,數(shù)據(jù)請求成功以后發(fā)送如下通知:

// 發(fā)送刷新紅點的通知
[[NSNotificationCenter defaultCenter] postNotificationName: YM_STORE_ORDER_WAIT_COUNT object:nil];

StoreTopBarTool中添加觀察者

//添加觀察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshCount:) name: YM_STORE_ORDER_WAIT_COUNT object:nil];
//通知中方法的實現(xiàn)
- (void)refreshCount:(NSNotification *)notification {
        something to do...
}

現(xiàn)象: 在 iOS8 系統(tǒng)下由于存在未被釋放的通知,當(dāng)重復(fù)發(fā)送通知的時候發(fā)生崩潰
原因: 沒有在 dealloc 中移除通知
解決辦法: 在接受通知的類或者界面里的delloc方法中移除通知,如下:
StoreTopBarTooldealloc方法中移除觀察者

- (void)dealloc {
    //移除刷新紅點的通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:YM_STORE_ORDER_WAIT_COUNT object:nil];
}

注意:

  1. -(void)addObserver-(void)removeObserver方法中的self必須是同一個對象.
  2. 對于此次崩潰,筆者反復(fù)驗證,在 iOS9/10下并不會發(fā)生,具體什么原因可參考蘋果其官方文檔中的一段話:iOS9 中,NSNotificationCenter將不再會對一個已經(jīng)被釋放掉的observer發(fā)送通知.
    In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter 
will no longer send notifications to registered observers that may be deallocated.

更多關(guān)于 iOSNSNotification 的用法可參考
iOS通知機制
iOS NSNotificationCenter 使用姿勢詳解


記一次Block死循環(huán)事故

筆者在一次開發(fā)過程中,不小心在定時器結(jié)束的 Block 中回調(diào)的時候又重置了定時器導(dǎo)致,從而引發(fā)了這次死循環(huán)血案,導(dǎo)致三位測試小伙伴的 iPad/iPhone 直接bong~關(guān)機...

self.timeCountView.timeStopBlock = ^{
// 倒計時結(jié)束,關(guān)閉定時器.
    dispatch_source_cancel(_timer);
        _timer = nil;
        dispatch_async(dispatch_get_main_queue(), ^{
             if (self.timeStopBlock) {
                 self.timeStopBlock();
             }
        });
}

附: 關(guān)于 Block 循環(huán)引用的相關(guān)案例可以參考這篇文章iOS容易造成循環(huán)引用的三種場景,就在你我身邊!

Block 塊回調(diào)定位
// Block 重命名
typedef void(^LocationBlock)(NSIndexPath *indexPath);

// .h聲明屬性
@property (nonatomic, strong) LocationBlock locationBlock;

// .m傳值
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:section];
    if (self.locationBlock) {
        self.locationBlock(indexPath);
}

// 在需要定位的地方回調(diào)Block并實現(xiàn)定位
__weak UICollectionView *weakCollectionView = _collectionView;
_otherRecordListView.locationBlock = ^(NSIndexPath *indexPath){
    if (indexPath.item != 0 && weakSelf.itemData.count != 0) {
        [weakCollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:(UICollectionViewScrollPositionTop) animated:YES];
    }
};
GCD timer定時器
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒執(zhí)行
dispatch_source_set_event_handler(timer, ^{
    //@"倒計時結(jié)束煎谍,關(guān)閉定時器"
    dispatch_source_cancel(timer); 
    dispatch_async(dispatch_get_main_queue(), ^{

    });
});
//啟動定時器
dispatch_resume(timer);
跳轉(zhuǎn)至指定視圖控制器
for (UIViewController *vc in self.navigationController.viewControllers) {
    if ([vc isKindOfClass:[YourViewController class]]) {
        [self.navigationController popToViewController:vc animated:YES];
    }
}
由視圖找到其所在的控制器
- (UIViewController *)viewController
{
    for (UIView *next = [self superview]; next; next = next.superview) {
        UIResponder *nextResponder = [next nextResponder];
        if ([nextResponder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)nextResponder;
        }
    }
    return nil;
}
for (UIView *next = [self superview]; next; next = next.superview) {
        UIResponder *nextResponser = [next nextResponder];
        NSLog(@"%@", [nextResponser class]);
        if ([nextResponser isKindOfClass:[HomeView class]]) {
            HomeView *view = (HomeView *)nextResponser;
            break;
        }
}
移除指定的視圖控制器
for (UIViewController *vc in self.navigationController.childViewControllers) {
        if ([vc isKindOfClass:[YourSelfViewController class]]) {
                [vc removeFromParentViewController];
        }
}
addSubview和 insertSubView 區(qū)別
A addSubview B                    將B直接覆蓋在A的最上層
A insertSubView B AtIndex:2       將B插入到A的子視圖index為2的位置(最底下是0)
A insertSubView B aboveSubview:C  將B插入A并且在A已有的子視圖C的上面
A insertSubView B belowSubview:C  將B插入A并且在A已有的子視圖C的下面

Color轉(zhuǎn)Image

+(UIImage*) createImageWithColor:(UIColor*) color  
{  
    CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);  
    UIGraphicsBeginImageContext(rect.size);  
    CGContextRef context = UIGraphicsGetCurrentContext();  
    CGContextSetFillColorWithColor(context, [color CGColor]);  
    CGContextFillRect(context, rect);  
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext();  
    return theImage;  
}

網(wǎng)絡(luò)請求圖片并緩存至本地沙盒

// SD下載
__block typeof(self) weakSelf = self;
[_userHeadBtn sd_setImageWithURL:[NSURL URLWithString:userInfo.avatarUrl] forState:UIControlStateNormal placeholderImage:headImage options:SDWebImageRetryFailed|SDWebImageContinueInBackground completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
    if (image) {
       [weakSelf saveUserHeadImg:image andUserId:userId];
    }
 }];

// 緩存至本地沙盒
-(void)saveUserHeadImg:(UIImage *)headImg andUserId:(NSInteger)userId
{
    if (userId == 0) {
        return;
    }
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
    NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"%ziavatar.png",userId]];
    if (filePath && headImg)
    {
        [UIImagePNGRepresentation(headImg)writeToFile: filePath atomically:YES]; // 保存成功會返回YES
    }
}
檢驗字符串是否是郵箱
+ (BOOL)isValidateEmail:(NSString *)email {
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    return [emailTest evaluateWithObject:email];
}
MD5加密字符串
+(NSString *)getMD_5_Str:(NSString *)str {

    NSMutableString *md5Str = [[NSMutableString alloc]initWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    const char *cStr = [str UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
    
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [md5Str appendString:[NSString stringWithFormat:@"%02x",result[i]]];
    }
    
    return md5Str;
}

開發(fā)工具鏈接

SimPholders_2.2(解壓密碼xclient.info) 密碼:uyws
dSYM文件分析工具 密碼:vtce
自定義貝塞爾曲線值的Mac工具

打包APP時報錯 linker command failed with exit code 1 (use -v to see invocation)
Build Settings中攘蔽,把 Enable Bitcode 設(shè)置為 NO
若顯示**xxx.app已損壞,打不開.你應(yīng)該將它移到廢紙簍 **

解決辦法:

  • 修改系統(tǒng)配置:系統(tǒng)偏好設(shè)置... -> 安全性與隱私。修改為任何來源
  • 如果沒有這個選項的話(macOS Sierra 10.12),打開終端呐粘,行命令: sudo spctl --master-disable
Xcode相關(guān)
// Xcode8注釋快捷鍵失效
解決方法:命令運行 sudo /usr/libexec/xpccachectl ,然后必須重啟電腦后生效

// Xcode模擬器緩存路徑
~/Library/Developer/Xcode/DerivedData/ModuleCache
防止谷歌自動跳轉(zhuǎn)到香港google.com.hk解決辦法

具體做法:在網(wǎng)址欄打入http://www.google.com/ncr满俗,然后回車即可。如果清理了Cookies緩存作岖,還是出現(xiàn)自動跳轉(zhuǎn)現(xiàn)象唆垃,重新再在網(wǎng)址欄打入http://www.google.com/ncr輸入,回車就行
ncr 是 no country redirection痘儡,是強制不跳轉(zhuǎn)命令

git push 時報以下信息,使用命令后依然無法解決:

fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

Jietu20170705-115347.jpg

解決辦法 : 如果不想重新創(chuàng)建遠程倉庫再克隆辕万,或者初始化本地倉庫,可以使用下面命令:
git push -u origin master沉删,其中origin 表示遠程倉庫名稱渐尿,master是遠程倉庫的push目標(biāo)分支。-u (推測為update縮寫_~) 表示本地分支將建立對遠程倉庫目標(biāo)分支的檢測矾瑰,如果遠程倉庫目標(biāo)分支不存在砖茸,將新建分支再push;如果存在殴穴,將進行push更新

Instead of creating a new repository on Github, cloning that, or reinitializing your local repository, the following command would have been sufficient:
git push -u origin master
origin stands for the remote name (default is origin), and master is the branch you want to push, in your case it's master, otherwise you would have to change that in the command.
-u means, that your local branch will be setup to track the new created master branch on the origin repository (the master on the origin will be the upstream branch of your local branch). If the branch master doesn't exist on the remote repository, it will be created, otherwise it will be updated (the -u works no matter if it exists or not).

然后凉夯,驗證此方法货葬,確實可行!

Jietu20170705-120044.jpg

引自

npm執(zhí)行命令時出錯

npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules/gitbook/node_modules/abab'
npm ERR!  { [Error: EACCES: permission denied, access '/usr/local/lib/node_modules/gitbook/node_modules/abab']
npm ERR!   stack:
npm ERR!    'Error: EACCES: permission denied, access \'/usr/local/lib/node_modules/gitbook/node_modules/abab\'',
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/local/lib/node_modules/gitbook/node_modules/abab' }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).

原因: 沒有獲得管理員權(quán)限.
解決辦法: 在命令前輸入 sudo 然后按提示輸入密碼即可.

雜七雜八鏈接

藍牙學(xué)習(xí) 博客
icon網(wǎng)站
實用代碼段
iOS 開發(fā)之照片框架詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劲够,一起剝皮案震驚了整個濱河市宝惰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌再沧,老刑警劉巖尼夺,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異炒瘸,居然都是意外死亡淤堵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門顷扩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拐邪,“玉大人,你說我怎么就攤上這事隘截≡祝” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵婶芭,是天一觀的道長东臀。 經(jīng)常有香客問我,道長犀农,這世上最難降的妖魔是什么惰赋? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮呵哨,結(jié)果婚禮上赁濒,老公的妹妹穿的比我還像新娘。我一直安慰自己孟害,他們只是感情好拒炎,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挨务,像睡著了一般击你。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耘子,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天果漾,我揣著相機與錄音,去河邊找鬼谷誓。 笑死,一個胖子當(dāng)著我的面吹牛吨凑,可吹牛的內(nèi)容都是我干的捍歪。 我是一名探鬼主播户辱,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼糙臼!你這毒婦竟也來了庐镐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤变逃,失蹤者是張志新(化名)和其女友劉穎必逆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揽乱,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡名眉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凰棉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片损拢。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖撒犀,靈堂內(nèi)的尸體忽然破棺而出福压,到底是詐尸還是另有隱情,我是刑警寧澤或舞,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布荆姆,位于F島的核電站,受9級特大地震影響映凳,放射性物質(zhì)發(fā)生泄漏胞枕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一魏宽、第九天 我趴在偏房一處隱蔽的房頂上張望腐泻。 院中可真熱鬧,春花似錦队询、人聲如沸派桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铆惑。三九已至,卻和暖如春送膳,著一層夾襖步出監(jiān)牢的瞬間员魏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工叠聋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撕阎,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓碌补,卻偏偏與公主長得像虏束,于是被迫代替她去往敵國和親棉饶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348