推荐其他链接:

md5

objective-c计算md5的方法:

- (NSString *) md5:(NSString *) input
{
    const char *cStr = [input UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5( cStr, strlen(cStr), digest );
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];
    return  output;
}

对应java的DES/CBC/PKCS5Padding加密算法

ios默认提供PKCS7Padding加密,但是 java时PKCS5Padding,所以需要fixkey,完整方法:

-(NSString *)encrypt:(NSString*)input WithKey:(NSString *)key{
    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;
    
    NSMutableData *keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
    NSMutableData *ivData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
    NSData *inputData=[input dataUsingEncoding:NSUTF8StringEncoding];
    [keyData setLength: 8];//非常重要!!!iOS默认API是PKCS7Padding,而java是PKCS5Padding
    
    status = CCCryptorCreate( kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
                             [keyData bytes], [keyData length], [ivData bytes],
                             &cryptor );
    
    size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[inputData length], true );
    void * buf = malloc( bufsize );
    size_t bufused = 0;
    size_t bytesTotal = 0;
    status = CCCryptorUpdate( cryptor, [inputData bytes], (size_t)[inputData length],
                             buf, bufsize, &bufused );
    bytesTotal += bufused;
    status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused );
    bytesTotal += bufused;
    NSData *outputData=[NSData dataWithBytesNoCopy: buf length: bytesTotal] ;
    
    //NSData 转换成16进制字符串
    const unsigned char *dataBuffer = (const unsigned char *)[outputData bytes];
    NSUInteger          dataLength  = [outputData length];
    NSMutableString     *hexString  = [NSMutableString stringWithCapacity:(dataLength * 2)];
    for (int i = 0; i < dataLength; ++i)
        [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
    
    return [NSString stringWithString:hexString];
}

不响应屏幕旋转

/*ipad 不旋转。*/
- (BOOL)shouldAutorotate {
    return NO;
}

应用闪退

打开应用后,直接闪退,肯定是App crash了,并且不出现在UI上,一般可以检查AppDelegate里面的方法调用,比如网络异常等,如果没有try-catch都有可能导致App直接崩溃。

Xcode调试中失去连接

xcode启动程序以后,断开连接,这是证书原因。debug 的时候不能用distribute证书。另外,如果有today extension之类的,这是一个新的target,需要单独设置证书:

xcode设置target

自动转换类型的问题

比如下面的代码:

#  import <Foundation/Foundation.h>
int main(int argc,const char *argv[]){
	NSArray *items = @[@1, @2, @3];
	for (int i = -1; i < items.count; i++) {
	    NSLog(@"%d", i);
	}
}

编译运行gcc -ObjC -framework Foundation test.m && ./a.out我们发现,什么也没有输出。这是因为,在for循环中,items.count是NSUInteger(typedef unsigned long NSUInteger)类型的,-1被强制转换,变成一个很大的数。

iOS7 企业账号发布应用出现两个图标

两个图标

这个问题出在plist上,google了一番,有的说是bundle id不一致导致的,但是亲测,bundle id即使一致,也存在这个问题。最后发现是metadatatitle的问题,我这个和com.xidibuy.moa中的moa一致。会出现两个图标,

其中一个正在安装的图标是删不掉的。发布一个新应用(xcode新建一个)bundle id设置成和原来的一样。然后adhoc发布,安装。这时候不论是否安装成功,都会覆盖掉原来的,这样就能删除了。

xcode6 新建的应用在iOS7下出现上下黑边

因为xcode6种启动屏改成了LaunchScreen.xib,所以就没有了Default-568h@2x.png,这样在iOS7下,系统就认为不支持iPhone5的分辨率,所以按iPhone4的分辨率启动了,产生黑边。

键盘问题

首先是点击其他地方,键盘隐藏

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

键盘uiwebview样式,可以上一个/下一个,不隐藏uitextfield。用https://github.com/hackiftekhar/IQKeyboardManager,只需要pod install,什么也不需要做。

更精确的sizeclass

sizeclass的屏幕区分粒度还是不大,比如,如果想区分iPhone4和iPhone5屏幕,直接用sizeclass就很困难。这时候可以用: xcode constaints也能connect

- (void)updateViewConstraints {
    [super updateViewConstraints];
    if ([UIScreen mainScreen].bounds.size.height<=480) {
        self.bgConstraint.constant=100;
    }
}

自定义字体不加载

要加载自定义字体,除了要在Info.plist里面加入:

<key>UIAppFonts</key>
	<array>
		<string>xidi.ttf</string>
	</array>

还需要在Build Phases->Copy Bundle Resources里面添加该字体。然后遍历字体名称:

  for (NSString* family in [UIFont familyNames])
    {
        NSLog(@"%@", family);
        for (NSString* name in [UIFont fontNamesForFamilyName: family])
        {
            NSLog(@"  %@", name);
        }
    }

xcode在异常处中断

cmd+7,新建(+)breakpoint

SDWebImage修改全局useragent

所有的image都是在SDWebImageDownloader里面下载的,修改downloadImageWithURL方法里面的NSMutableURLRequest即可 首先添加两个属性:

//by logan useragent
@property NSString *currentDate;
@property NSString *userAgent;
//然后
 //131 行 ,by logan override useragent;
        NSDateFormatter *formatter = [NSDateFormatter new];
        formatter.dateFormat=@"yyyy-MM-dd";
        NSString *theDate= [formatter stringFromDate:[NSDate new]];
        if (![theDate isEqualToString:wself.currentDate ]) {
            wself.currentDate=theDate;
            const char *cStr = [theDate UTF8String];
            unsigned char digest[CC_MD5_DIGEST_LENGTH];
            CC_MD5( cStr, (unsigned int)strlen(cStr), digest );
            NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
            for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
                [output appendFormat:@"%02x", digest[i]];
            wself.userAgent=[@"XidiApp/iOS " stringByAppendingString:output];
        }
        [request setValue:wself.userAgent forHTTPHeaderField:@"User-Agent"];

uiwebview开启远程调试

只能在模拟器中使用,就像firebug一样。我们可以通过mac上的Safari调试uiwebview中的html和js。需要在appdelegate中的didFinishLaunchingWithOptions中加入:

#  if (TARGET_IPHONE_SIMULATOR)
    [NSClassFromString(@"WebView") performSelector:@selector(_enableRemoteInspector)];
#  endif

然后启动mac上的Safari,偏好设置->高级->在菜单中显示“开发”菜单。进入 开发->iOS simulator即可

Reveal再来30天

~/Library/Preferences/com.ittybittyapps.Reveal.plist 删除了就能再用 30 天。

但是如果已经过超过了30天,这种方法就不行了。可以通过用xcode编辑/Applications/Reveal.app/Contents/Info.plist中的Bundle identifier,然后重启Reveal再来30天。此时,也可以直接重装一下。 为了方便,可以写一个定时任务,每天清除一下com.ittybittyapps.Reveal.plist。

UIScrollView滚动完成回调

自动触发scroll,比如使用scrollRectToVisible或者setContentOffset,回调scrollViewDidEndScrollingAnimation;手动拖拽出发scrollViewDidEndDecelerating

给uiview添加MotionEffect

就像在Home页的壁纸,随着手机角度移动,壁纸会动。

UIInterpolatingMotionEffect * xEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
xEffect.minimumRelativeValue =  [NSNumber numberWithFloat:-40.0];
xEffect.maximumRelativeValue = [NSNumber numberWithFloat:40.0];
[img addMotionEffect:xEffect];

UIview可以add的其他东西

OC的getter和setter方法命名

默认情况下,属性的getter方法用属性名,而不是getXxx。比如:

[[UILabel new]font];
[[UILabel new]setFont:nil]

在Cocoa中,一般用getXxx的参数表示返回值存放的位置。比如NSData中的:

- (void)getBytes:(void *)buffer/*指针*/;

这是命名惯例,希望遵守

获取正在运行的程序

#  import <sys/sysctl.h>


- (NSArray *)runningProcesses {
    
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t miblen = 4;
    
    size_t size;
    int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
    
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
    
    do {
        
        size += size / 10;
        newprocess = realloc(process, size);
        
        if (!newprocess){
            
            if (process){
                free(process);
            }
            
            return nil;
        }
        
        process = newprocess;
        st = sysctl(mib, miblen, process, &size, NULL, 0);
        
    } while (st == -1 && errno == ENOMEM);
    
    if (st == 0){
        
        if (size % sizeof(struct kinfo_proc) == 0){
            int nprocess = size / sizeof(struct kinfo_proc);
            
            if (nprocess){
                
                NSMutableArray * array = [[NSMutableArray alloc] init];
                
                for (int i = nprocess - 1; i >= 0; i--){
                    
                    NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
                    NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];
                    
                    NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName, nil]
                                                                        forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName", nil]];
                   
                    [array addObject:dict];
                }
                
                free(process);
                return array;
            }
        }
    }
    
    return nil;
}

 NSArray * processes = [self runningProcesses];
    for (NSDictionary * dict in processes){
        NSLog(@"%@ - %@", [dict objectForKey:@"ProcessID"], [dict objectForKey:@"ProcessName"]);
    }

获取所有已经安装的app

#  include <objc/runtime.h>

Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
NSLog(@"apps: %@", [workspace performSelector:@selector(allApplications)]);

UIAlertView 在springboard弹出

使用 CFUserNotificationCreate()CFUserNotificationReceiveResponse()

UItableview刷新cell高度

 [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:textField.tag+1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

UIWebview和NSURLConnection功用一个cookiestore

这一点非常好用。可以更好地让native和h5页面交互,无需自己处理cookie

Xcode->debug菜单很强大

比如截屏(保存到桌面),view frame bounds等。可以设置快捷键。非常方便

objc category全局改变backBarButtonItem

#  import "UINavigationItem+XDNav.h"

@implementation UINavigationItem (XDNav)
-(UIBarButtonItem*)backBarButtonItem{
    return [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
@end

通过类的categoery简化

比如

@import UIKit;
@interface UIColor (AAPLApplicationSpecific)
+ (UIColor *)aapl_applicationGreenColor;
+ (UIColor *)aapl_applicationBlueColor;
+ (UIColor *)aapl_applicationPurpleColor;
@end

这样可以定义全局的颜色

解析url参数和base64编码

+(NSDictionary *)parseUrl:(NSURL*)url{
    NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] init];
    NSArray *urlComponents = [[url query] componentsSeparatedByString:@"&"];
    
    for (NSString *keyValuePair in urlComponents)
    {
        NSRange range=[keyValuePair rangeOfString:@"="];
        [queryStringDictionary setObject:range.length>0?[keyValuePair substringFromIndex:range.location+1]:@"" forKey:(range.length?[keyValuePair substringToIndex:range.location]:keyValuePair)];
    }
    NSLog(@"-----\n%@\n%@",url,queryStringDictionary);
    return queryStringDictionary;
}
+(NSString*)base64Encode:(NSString *)input{
    NSString *base64Encoded = [[input
                                dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
    return base64Encoded;
}

Code Sign error: Provisioning profile XXXX can’t be found

切换了账号以后,切换provisioning profile,无论怎么刷新都不行。vi project.pbxproj 找到提示找不到的那个profile,删除那一行即可。

weak–strong dance

__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf)strongSelf = weakSelf;
    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
        strongSelf.networkReachabilityStatusBlock(status);
    }
};

设置背景图片

对于不提供view.backgroundimage的类,可以用:

cell.layer.contents = (id)[UIImage imageNamed:@"space_bg.jpg"].CGImage;//fill模式
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"space_bg.jpg"]];//平铺模式

越狱设备查看bundle id

find /private/var/mobile/Containers/Data/Application/ -name Info.plist

cycript获取app的document目录

cycript -p TargetApp
[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]

LLDB技巧

bt all
breakpoint set -n "-[UIView setFrame:]"
po [[[[UIApplication sharedApplication] delegate] window] recursiveDescription]
po yourDataObject

NSAssert的使用

开发中对于内部的代码进行自检。推荐用NSAssert,在Release版本中,设置Preprocessor Macros->Release(NS_BLOCK_ASSERTIONS)可以关闭。另外通过修改schema(cmd+shift+.),可以让运行的schema用Release配置。

duplicate symbol OBJC_METACLASS$_ClassName

#import的时候引入了.m文件,而不是.h文件。

NSNotification必须配对出现

NSNotification有add,必须在dealloc中remove,否则会造成循环引用。另外注意 NSNotification 中的target是阻塞执行的。执行的线程和poster一致,如果想更新UI,注意应在main_thread中执行。

NSTimer定时任务必须invalidate

dealloc中必须把NSTimer清楚,否则造成循环引用