2017/0709lesson

Jul 9, 2017

2017/05/31

使用UIEffectView 的一个坑:UIEffectView的实现方式是将底部的着色吸附到当前View中。我喜欢使用帧动画,pop更加爱,于是出现一个情况,该effectView在上下滑动时,吸附的图片会出现在之前的位置,很不稳定,估计是使用局部变量编写,然后没有着色在之前的rect上面,出现有刷新当前区域指令的时候,就会清楚这块不稳定内容。
这个问题重点在动画上。pop帧动画,采用逐步转移,而不是我现在解决使用的UIView动画。UIView动画是点到终点的动画,而pop是过程可逆的过程动画。

这里记录一次ASDK中滑动卡顿一愣一愣,以及push卡顿。

ASDK滑动卡顿解决过程,使用将其他因素全部关掉方法。心里解决难,是因为其还有其他可能卡顿因素,所以不觉得是因为在ASDK内容物问题,因为试图由好几个层级嵌套合成。真正卡顿在ASCellNode里面,由于设计图要有cornerRadius ,单元格要有shadow,于是我加在didLoad方法里面。但是每次滑动过程,可能走到了shadow 过程,于是试图又尝试算了一遍。
push卡顿问题,首先要理解试图从创建过程,到压栈完成的流程。首先走init方法、接着走pushViewcontroller、viewDidLoad方法、然后走push压栈动画、最后viewwillappear。由于压栈动画是要有主线程的,当然viewDidLoad中也是有主线程卡主,那么也会有进入很慢的过程。
这次是因为我加了一个小方法->使用SVGKit 加载一个svg 然后转成image过程。在其中一个UIView的子UIButton使用了该转换的Image,于是我一次次打log,计算时间消耗,该处消耗0.6s,而且是在主线程,于是该处出现了卡顿。

锤子和钉子,工具和需求

前两天在看数据库Realm,后半段功能。然不尽了解内里,所以想问公司其他人了解我所不了解的需求完成过程。但是和他们说的过程中,博士一句话点醒了我:钉子是先存在的,然后找到了锤子解决;而不是拿着锤子寻找钉子。给我的醒悟是,如果我一开始还没有钉子(后半段功能产生的需求),却急于找到锤子,那么没有钉子的需求,很快我也将忘了锤子;所以我慢了下来:在目前碰到的钉子,使用一个个不同的锤子解决。

记录一次碰到僵尸代码以及解决过程

当前页面是这样:push到的DetailVC 有navigationDelegate,作为转场代理,DetailVC操作完进入“完成、分享页面”,然后有这一份代码:

1
2
self.tabBarController.selectedIndex = 1;
[self.navigationController popToRootViewControllerAnimated:NO];

让其转向tabbar为1(之前tabbarindex=0),然后popToRootVC;这里引导出了一个问题,我再点击Tabbar=0时,此时的navigationDelegate还是detailVC,但是却早已经被dealloc了,于是就崩溃。解决是viewwillDisappear处将navigationDelegate置空。
OK,代码解决为之上处理,但是一开始碰到这个crash的时候,程序什么提示都没有,直接进入AppDelegate的“Bad Access XXXX”。查阅资料: :你得先知道哪报错,按下面设一下,结合日志,先找到错误的代码,
设置NSZombieEnabled、MallocStackLogging、NSAutoreleaseFreedObjectCheckEnabled、NSDebugEnabled:

1
2
3
4
5
1. Product->Edit Scheme...->Run...->EnvironmentVariables. 
2. add NSZombieEnabled,set the value with YES
3. add MallocStackLogging, set the value with YES.
4. add NSAutoreleaseFreedObjectCheckEnabled, set the value with YES.
5. add NSDebugEnabled, set the value with YES.

这时程序console才会打出说*** -[XXXXXViewC respondsToSelector:]: message sent to deallocated instance 0x134ed5900
这时又借鉴这两篇文章:

后一篇跟我的很类似,都是根据VC 和 delegate 之间的关系。然后得以解决

library not found for -lcrt

出现这个错误,是因为你的测试版本号太高了,以前Demo的版本低于你能运行的版本,解决:Targets->General->Deployment Info->Deployment Target改为当前Xcode能运行的最低版本

[viewModel.xxxCommand execute]在其返回executionSignals之前调用,不会走executionSignal方法

今天调试一个网络,由于试试写法execute方法,这次将其写在executionSignals之前,怎么都不会走,我怎么看写法都不可能错,在将挂起方法:execute写到后面才走。在此记录一个,有机会再看是什么缘由。

iOS跳转到具体某个应用的设置

http://blog.csdn.net/jsjxiaobing/article/details/51260753

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
NSString * UIApplicationOpenSettingsURLString = @"prefs:root=WIFI";  
NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}

About — prefs:root=General&path=About
Accessibility — prefs:root=General&path=ACCESSIBILITY
AirplaneModeOn— prefs:root=AIRPLANE_MODE
Auto-Lock — prefs:root=General&path=AUTOLOCK
Brightness — prefs:root=Brightness
Bluetooth — prefs:root=General&path=Bluetooth
Date& Time — prefs:root=General&path=DATE_AND_TIME
FaceTime — prefs:root=FACETIME
General— prefs:root=General
Keyboard — prefs:root=General&path=Keyboard
iCloud — prefs:root=CASTLE iCloud
Storage & Backup — prefs:root=CASTLE&path=STORAGE_AND_BACKUP
International — prefs:root=General&path=INTERNATIONAL
Location Services — prefs:root=LOCATION_SERVICES
Music — prefs:root=MUSIC
Music Equalizer — prefs:root=MUSIC&path=EQ
Music VolumeLimit— prefs:root=MUSIC&path=VolumeLimit
Network — prefs:root=General&path=Network
Nike + iPod — prefs:root=NIKE_PLUS_IPOD
Notes — prefs:root=NOTES
Notification — prefs:root=NOTIFICATIONS_ID
Phone — prefs:root=Phone
Photos — prefs:root=Photos
Profile — prefs:root=General&path=ManagedConfigurationList
Reset — prefs:root=General&path=Reset
Safari — prefs:root=Safari Siri — prefs:root=General&path=Assistant
Sounds — prefs:root=Sounds
SoftwareUpdate— prefs:root=General&path=SOFTWARE_UPDATE_LINK
Store — prefs:root=STORE
Twitter — prefs:root=TWITTER
Usage — prefs:root=General&path=USAGE
VPN — prefs:root=General&path=Network/VPN
Wallpaper — prefs:root=Wallpaper
Wi-Fi — prefs:root=WIFI
Setting—prefs:root=INTERNET_TETHERING

记一次Instrument - Time Profile 过程

xcode 8.+在使用Time Profile中,会出现信息不完整,没法指示更多有用的信息。
首先由这篇文章:http://www.cnblogs.com/ym123/p/4324335.html能明白大概操作内容。在xcode 8.+中,CallTree被移动到最下方而不是右下角处。然后跟着走的时候,并没有显示文章中说的图标为黑色头像的就是Time Profiler给我们的提示,有可能存在性能瓶颈的地方,可以逐渐向下展开,找到产生的根本原因。这个;
我又找了找这篇文章:http://www.jianshu.com/p/179d69f636b0
原来是需要在Target-Build Settings-Debug Information Format-Debug 选择dwarf-with-dsym,如果没有该选项,需要手动打入。
同时开启TimeProfile就可以看到黑色头像,同时各个方法调用栈就出来。
我的操作是:先点击你需要debug的附近区域,然后CPU Usage会有很多波动,然后你可以暂停(stop,不是shut down)同时选中该波动区域附近,形成一个区间。然后下方的调用栈即为该时间区域的调用信息。即得到所需要信息。

记一次硬磕UI、转场遇到的问题

1:转场的时候alpha很重要,比如pushTransitino的时候,toVC的alpha一开始就要设好,如果animate组,半途还有转变动画,那么会带来感觉像是掉帧的bug。fromVC也一样,多调试这一块,结合Time Profile看这中间有没有其他重操作,提前做,或者之后做。
2:pop的时候,与push很像。这里提一点,动作与控制要同步,比如转场里面某一元素,如果动画场景不一致,会带来断层,中间的东西没了,然后又有了。比如我后退,立马把该元素隐藏,但是等到要做动画其实还要几毫秒,于是就会出现断层。这时候最好的就是先在contextView中添好该元素试图覆盖,然后再隐藏。
多用动画稿,尽量不要埋头苦调试,没有数值真的很麻烦。

昨晚看到一个帖子列出好的一些iOS片段,我继续删减,留下适合我,我可能会遇到的

去除数组中重复的对象

NSArray *newArr = [oldArr valueForKeyPath:@“@distinctUnionOfObjects.self"];

动画切换window的根控制器
1
2
3
4
5
6
7
8
// options是动画选项
[UIView transitionWithView:[UIApplication sharedApplication].keyWindow duration:0.5f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
        BOOL oldState = [UIView areAnimationsEnabled];
        [UIView setAnimationsEnabled:NO];
        [UIApplication sharedApplication].keyWindow.rootViewController = [RootViewController new];
        [UIView setAnimationsEnabled:oldState];
    } completion:^(BOOL finished) {
    }];
由角度转换弧度

`

#define DegreesToRadian(x) (M_PI * (x) / 180.0)
`

控制屏幕旋转,在控制器中写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** 是否支持自动转屏 */
- (BOOL)shouldAutorotate {
    return YES;
}
 
/** 支持哪些屏幕方向 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
 
/** 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法) */
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}
几个常用权限判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    if ([CLLocationManager authorizationStatus] ==kCLAuthorizationStatusDenied) {
        NSLog(@"没有定位权限");
    }
    AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (statusVideo == AVAuthorizationStatusDenied) {
        NSLog(@"没有摄像头权限");
    }
    //是否有麦克风权限
    AVAuthorizationStatus statusAudio = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    if (statusAudio == AVAuthorizationStatusDenied) {
        NSLog(@"没有录音权限");
    }
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status == PHAuthorizationStatusDenied) {
            NSLog(@"没有相册权限");
        }
    }];
判断图片类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//通过图片Data数据第一个字节 来获取图片扩展名
- (NSString *)contentTypeForImageData:(NSData *)data
{
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c)
    {
        case 0xFF:
            return @"jpeg";
 
        case 0x89:
            return @"png";
 
        case 0x47:
            return @"gif";
 
        case 0x49:
        case 0x4D:
            return @"tiff";
 
        case 0x52:
        if ([data length] < 12) {
            return nil;
        }
 
        NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
        if ([testString hasPrefix:@"RIFF"]
            && [testString hasSuffix:@"WEBP"])
        {
            return @"webp";
        }
 
        return nil;
    }
 
    return nil;
}
获取手机和app信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];  
 CFShow(infoDictionary);  
// app名称  
 NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];  
 // app版本  
 NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];  
 // app build版本  
 NSString *app_build = [infoDictionary objectForKey:@"CFBundleVersion"];  
 
 
 
    //手机序列号  
    NSString* identifierNumber = [[UIDevice currentDevice] uniqueIdentifier];  
    NSLog(@"手机序列号: %@",identifierNumber);  
    //手机别名: 用户定义的名称  
    NSString* userPhoneName = [[UIDevice currentDevice] name];  
    NSLog(@"手机别名: %@", userPhoneName);  
    //设备名称  
    NSString* deviceName = [[UIDevice currentDevice] systemName];  
    NSLog(@"设备名称: %@",deviceName );  
    //手机系统版本  
    NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];  
    NSLog(@"手机系统版本: %@", phoneVersion);  
    //手机型号  
    NSString* phoneModel = [[UIDevice currentDevice] model];  
    NSLog(@"手机型号: %@",phoneModel );  
    //地方型号  (国际化区域名称)  
    NSString* localPhoneModel = [[UIDevice currentDevice] localizedModel];  
    NSLog(@"国际化区域名称: %@",localPhoneModel );  
 
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];  
    // 当前应用名称  
    NSString *appCurName = [infoDictionary objectForKey:@"CFBundleDisplayName"];  
    NSLog(@"当前应用名称:%@",appCurName);  
    // 当前应用软件版本  比如:1.0.1  
    NSString *appCurVersion = [infoDictionary objectForKey:@"CFBundleShortVersionString"];  
    NSLog(@"当前应用软件版本:%@",appCurVersion);  
    // 当前应用版本号码   int类型  
    NSString *appCurVersionNum = [infoDictionary objectForKey:@"CFBundleVersion"];  
    NSLog(@"当前应用版本号码:%@",appCurVersionNum);
获取设备mac地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
+ (NSString *)macAddress {
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
 
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
 
    if((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
 
    if(sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
 
    if((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. Rrror!\n");
        return NULL;
    }
 
    if(sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
 
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"X:X:X:X:X:X",
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
 
    return outstring;
}
拿到当前正在显示的控制器,不管是push进去的,还是present进去的都能拿到
1
2
3
4
5
6
7
8
9
10
11
12
13
- (UIViewController *)getVisibleViewControllerFrom:(UIViewController*)vc {
    if ([vc isKindOfClass:[UINavigationController class]]) {
        return [self getVisibleViewControllerFrom:[((UINavigationController*) vc) visibleViewController]];
    }else if ([vc isKindOfClass:[UITabBarController class]]){
        return [self getVisibleViewControllerFrom:[((UITabBarController*) vc) selectedViewController]];
    } else {
        if (vc.presentedViewController) {
            return [self getVisibleViewControllerFrom:vc.presentedViewController];
        } else {
            return vc;
        }
    }
}
AFNetworking监听网络状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 监听网络状况
    AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
    [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                break;
            case AFNetworkReachabilityStatusNotReachable: {
                [SVProgressHUD showInfoWithStatus:@"当前设备无网络"];
            }
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                [SVProgressHUD showInfoWithStatus:@"当前Wi-Fi网络"];
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                [SVProgressHUD showInfoWithStatus:@"当前蜂窝移动网络"];
                break;
            default:
                break;
        }
    }];
    [mgr startMonitoring];
判断该图片是否有透明度通道
1
2
3
4
5
6
7
8
  - (BOOL)hasAlphaChannel
{
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
    return (alpha == kCGImageAlphaFirst ||
            alpha == kCGImageAlphaLast ||
            alpha == kCGImageAlphaPremultipliedFirst ||
            alpha == kCGImageAlphaPremultipliedLast);
}
获得灰度图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
+ (UIImage*)covertToGrayImageFromImage:(UIImage*)sourceImage
{
    int width = sourceImage.size.width;
    int height = sourceImage.size.height;
 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,kCGImageAlphaNone);
    CGColorSpaceRelease(colorSpace);
 
    if (context == NULL) {
        return nil;
    }
 
    CGContextDrawImage(context,CGRectMake(0, 0, width, height), sourceImage.CGImage);
    CGImageRef contextRef = CGBitmapContextCreateImage(context);
    UIImage *grayImage = [UIImage imageWithCGImage:contextRef];
    CGContextRelease(context);
    CGImageRelease(contextRef);
 
    return grayImage;
}
UILabel设置内边距
1
2
3
4
5
6
子类化UILabel,重写drawTextInRect方法
- (void)drawTextInRect:(CGRect)rect {
    // 边距,上左下右
    UIEdgeInsets insets = {0, 5, 0, 5};
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
让手机震动一下
1
2
3
4
5
倒入框架
#import
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
或者
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
摇一摇功能
1
2
3
4
5
6
7
8
9
10
11
12
1、打开摇一摇功能
    [UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
2、让需要摇动的控制器成为第一响应者
[self becomeFirstResponder];
3、实现以下方法
 
// 开始摇动
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
// 取消摇动
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
// 摇动结束
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
UITextView中打开或禁用复制,剪切,选择,全选等功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 继承UITextView重写这个方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
// 返回NO为禁用,YES为开启
    // 粘贴
    if (action == @selector(paste:)) return NO;
    // 剪切
    if (action == @selector(cut:)) return NO;
    // 复制
    if (action == @selector(copy:)) return NO;
    // 选择
    if (action == @selector(select:)) return NO;
    // 选中全部
    if (action == @selector(selectAll:)) return NO;
    // 删除
    if (action == @selector(delete:)) return NO;
    // 分享
    if (action == @selector(share)) return NO;
    return [super canPerformAction:action withSender:sender];
}

记录一个“POP”引擎动画后调用了superView的layoutSubViews方法

今天在做一个动画的时候,使用‘pop’时候,发现动作做完了,然后一个按钮使其回归原位,但是再做动作的时候,就只动了一下。难以查看过程,当我打断点到layoutSubviews的时候,果然进去了。然后不知道是谁调用的,于是我去使用time profile看了那一段时间干了什么事。于是看到了layoutSubviews被调用了,是‘pop’某一块调用了,使view又跑回原位。这时候,要么将布局代码写到其他地方,要么使用UIView的动画,我选择了后者。

POPSpringAnimation ‘scaleXY’ 会出现rotate 情况

在一个回馈动效中使用POPSpringAnimation,但是由于滑块可以快速多次滑动,所以在弹性高过预定值,会产生negative值,即负值,这时3D transform中,scaleXY会出现rotate情况,https://github.com/facebook/pop/issues/76,这里采用clamp,在结束时,不超过回弹值。可以使用下面给出的两端中其一都可:

1
2
3
4
5
6
7
8
-(void)popupMensionNode{
POPBasicAnimation *nodeAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
nodeAnim.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)];
nodeAnim.fromValue = [NSValue valueWithCGSize:CGSizeMake(0.f, 0.f)];
nodeAnim.autoreverses = YES;
nodeAnim.duration = 0.25;
[_textNode.layer pop_addAnimation:nodeAnim forKey:NSStringFromSelector(_cmd)];
}

1
2
3
4
5
6
7
8
9
10
-(void)popupMensionNode{
POPSpringAnimation *imageNodeAnim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
imageNodeAnim.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)];
imageNodeAnim.fromValue = [NSValue valueWithCGSize:CGSizeMake(0.f, 0.f)];
imageNodeAnim.autoreverses = YES;
imageNodeAnim.clampMode = kPOPAnimationClampEnd;
imageNodeAnim.springBounciness = 8;
// imageNodeAnim.springSpeed = 20;
[_textNode.layer pop_addAnimation:imageNodeAnim forKey:NSStringFromSelector(_cmd)];
}

上面两个带来的效果还是不尽完美,这时可以更进一步,又要同时有Spring动画效果,又要有回弹,那么只能使用自主操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-(POPSpringAnimation *)popupMensionNode{
[_popNode.layer pop_removeAllAnimations];

POPSpringAnimation *nodeAnim = self.popNodeAnima;
nodeAnim.fromValue = [NSValue valueWithCGSize:CGSizeMake(0.f, 0.f)];
nodeAnim.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)];
// nodeAnim.autoreverses = YES;
nodeAnim.springBounciness = 6;
[_popNode.layer pop_addAnimation:nodeAnim forKey:NSStringFromSelector(_cmd)];

POPBasicAnimation *minScaleXYAnimate = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
minScaleXYAnimate.duration = .2;
minScaleXYAnimate.toValue = [NSValue valueWithCGSize:CGSizeMake(0.f, 0.f)];

[nodeAnim setCompletionBlock:^(POPAnimation *animation,BOOL complete){
if (complete) {
[_popNode.layer pop_addAnimation:minScaleXYAnimate forKey:@"kminScaleAnimate"];
}
}];

return nodeAnim;
}
-(POPSpringAnimation *)popNodeAnima{
if (!_popNodeAnima) {
_popNodeAnima = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
}
return _popNodeAnima;
}

这样子便不会出现negative值,不会发生rotate,同时还保留有spring动画的停顿效果,多次快速点击也能相应,不会出问题。

更换PinRemoteImage已经保存的图片

这种做法比较少,但是还是会有此需求,比如我现在做的。
要更换就要更换两处,memory cache 和disk cache。

1
2
3
4
5
PINRemoteImageManager *imageManager = [PINRemoteImageManager sharedImageManager];
[imageManager.cache removeObjectForKeyFromMemory:model.img_url];
NSData *data = UIImagePNGRepresentation(para1.contentImg);
[imageManager.defaultImageCache setObjectInMemory:data forKey:model.img_url withCost:data.length];
[imageManager.cache setObjectOnDisk:data forKey:model.img_url];

model.img_url 是其地址,在disk->library->cache->pincache->com.pinterest.pinremoteImage目录下,记不清其目录地址,大概是这样的。
data是我们要保存的图片的NSData 。

记一次Apple Develop center 加多个device id经历

1:首先先下载上面一段话的特殊字,写着实例文件。
2:然后我跟着写了其格式:
1)第一行为无效文字,苹果不填写,仅做log实例。
2)第二行开始,左边填写”devices id+’tab’+名称(名称全部用英文写,不要有中文符号,不要有空格,不要奇奇怪怪东西)”
3:然后上传基本就可以了

如果中间有出问题,尽量分段上传,这样就可以测试时什么个情况了

iOS解决bug几个方法

1:用代码管理,每天记录。如果有解决不了的bug,看看几天改了什么,站起来思考(不要坐着)有没有关联;
2:如果是在一个文件class 内,可以试试将无关联代码去掉,单方面测试要定位的问题;解决了再回退,最好保存一份文件;
3:在断点出左下角+号,有个Exceptions BreakPoint…,直接点击添加,然后运行时自动大部分会自动定位到目标代码;
4:如果有崩溃现象,会进入到调用栈,IDE的左上角的小页签会跑到第六个,调用栈里边,这里可以看到你最近的几个方法是怎么跳转的,比如你是哪个线程,调用了哪个栈方法,连续调了哪些方法等等,这个方法很能反应问题实质,你还可以点击到相应的方法,同时打出相应的属性,lldb是可用状态;其他线程的lldb,只能看,不能再记录那些线程的方法属性了;
5:看性能损耗,主要还是要看Time Profile;同时僵尸代码的崩溃监控;这个记录由上边的Instrument 记录有记录。