2013-09-28 02:09:23 u011690307 阅读数 3423
  • iOS开发-全面解析iOS蓝牙BLE4.0开发

    只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发

    3672 人正在学习 去看看 许英俊

最近项目有个棘手的问题--适配IOS7....

由于IOS7把整个内容区都上移了20,所以很多不是全屏的应用都不能很好的兼容,换用苹果文档的一句话就是说:如果你们原来的app就是全屏模式运行的,那你们几乎不用改,如果不是,那·····

改之前很有必要去阅读下苹果官方的《ios7过渡指南》http://t.cn/zRv5lQT  ,当然,也有人翻译了一份··如果那什么可以看中文的·· http://t.cn/zHDbDCz (吐槽下“实现方法是在Info.plist中加入键UIViewControllerBasedStatusBarAppearance,并设置值为YES。”这句话好像翻译反了··)

来说说问题,由于主要问题界面给默认全屏了···也就是说原来statusbar的20像素没了,所以如果想比较快速的适配ios7,比较好的做法是:


step 1 写个UIViewController的Category让UIViewController默认的wantsFullScreenLayout返回YES,同时edgesForExtendedLayout默认返回All,目的是让所有版本都统一全屏


.h代码如下

#import <UIKit/UIKit.h>

#ifndef __IPHONE_7_0
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
    UIRectEdgeNone   = 0,
    UIRectEdgeTop    = 1 << 0,
    UIRectEdgeLeft   = 1 << 1,
    UIRectEdgeBottom = 1 << 2,
    UIRectEdgeRight  = 1 << 3,
    UIRectEdgeAll    = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
};
#endif

@interface UIViewController (UIRectEdge)

//#ifndef __IPHONE_7_0
- (BOOL)automaticallyAdjustsScrollViewInsets;
- (void)setAutomaticallyAdjustsScrollViewInsets:(BOOL)b;
- (UIRectEdge)edgesForExtendedLayout;
- (void)setEdgesForExtendedLayout:(UIRectEdge)rect;
//#endif
@end

.m

#import "UIViewController+UIRectEdge.h"

#import <objc/runtime.h>

@implementation UIViewController (UIRectEdge)

static const char *kWantsFullScreenLayoutKey;

- (BOOL)wantsFullScreenLayout
{
    id v=objc_getAssociatedObject(self,&kWantsFullScreenLayoutKey);
    if (v!=nil) {
        return [v boolValue];
    }else{
        return YES;
    }
}

- (void)setWantsFullScreenLayout:(BOOL)b
{
    objc_setAssociatedObject(self, &kWantsFullScreenLayoutKey, @(b), OBJC_ASSOCIATION_ASSIGN);
}

static const char *kAutomaticallyAdjustsScrollViewInsetsKey;

- (BOOL)automaticallyAdjustsScrollViewInsets
{
    id v=objc_getAssociatedObject(self,&kAutomaticallyAdjustsScrollViewInsetsKey);
    if (v!=nil) {
        return [v boolValue];
    }else{
        return NO;
    }
}

- (void)setAutomaticallyAdjustsScrollViewInsets:(BOOL)b
{
    objc_setAssociatedObject(self, &kAutomaticallyAdjustsScrollViewInsetsKey, @(b), OBJC_ASSOCIATION_ASSIGN);
}


static const char *kEdgesForExtendedLayoutKey;

- (UIRectEdge)edgesForExtendedLayout
{
    id v=objc_getAssociatedObject(self,&kEdgesForExtendedLayoutKey);
    if (v!=nil) {
        return [v integerValue];
    }else{
        return UIRectEdgeAll;
    }
}

- (void)setEdgesForExtendedLayout:(UIRectEdge)rect
{
    objc_setAssociatedObject(self, &kEdgesForExtendedLayoutKey, @(rect), OBJC_ASSOCIATION_ASSIGN);
}

@end





step 2 然后写个UIApplication的category让5,6上状态栏底色消失.

照例直接贴代码

.h

#import <UIKit/UIKit.h>

@interface UIApplication (UI7)
+ (void)inject;
@end

.m
#import "UIApplication+UI7.h"
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>

#define _IOS_VERSION_UI7 ([[[UIDevice currentDevice] systemVersion] floatValue])

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_4_3
#error UI7NavigationBar doesn't support Deployement Target version < 4.3
#endif

@implementation UIApplication (UI7)

+ (void)inject
{
    Method originMethod=class_getInstanceMethod(self, @selector(setStatusBarStyle:));
    Method newMethod=class_getInstanceMethod(self, @selector(__setStatusBarStyle:));
    
    method_exchangeImplementations(originMethod, newMethod);
    
    originMethod=class_getInstanceMethod(self, @selector(setStatusBarStyle:animated:));
    newMethod=class_getInstanceMethod(self, @selector(__setStatusBarStyle:animated:));
    
    method_exchangeImplementations(originMethod, newMethod);
}

- (void)__setStatusBarStyle:(UIStatusBarStyle)style
{
    [self __setStatusBarStyle:style];
    if (style==UIStatusBarStyleBlackTranslucent) {
        [self hiddenStatusBarBackground:YES];
    }
}

-(void)__setStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated
{
    [self __setStatusBarStyle:style animated:animated];
    
    if (style==UIStatusBarStyleBlackTranslucent) {
        if (animated) {
            [self performSelector:@selector(hiddenStatusBarBackground:) withObject:@(YES) afterDelay:0.6];
        }else{
            [self hiddenStatusBarBackground:YES];
        }
    }
}

- (void)hiddenStatusBarBackground:(BOOL)hidden
{
    if(_IOS_VERSION_UI7<7){
        BOOL isStatusBarHidden=[[UIApplication sharedApplication] isStatusBarHidden];
        if (isStatusBarHidden) {
            [[UIApplication sharedApplication] setStatusBarHidden:NO];
        }
        UIView *statusbar=[[UIApplication sharedApplication] valueForKey:@"_statusBar"];
        NSArray *vs=[statusbar subviews];
        for (UIView *v in vs) {
            if ([v isKindOfClass:NSClassFromString(@"UIStatusBarBackgroundView")]) {
                statusbar=v;
                break;
            }
        }
        if (isStatusBarHidden) {
            [[UIApplication sharedApplication] setStatusBarHidden:YES];
        }
        if (hidden) {
            [statusbar setHidden:YES];
        }else{
            [statusbar setHidden:NO];
        }
    }
}

@end


step 3实现一个UINavigationBar的子类,让自定义效果更加简单

.h

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSUInteger, UI7NavBarSytle)
{
    UI7NavBarSytleLight, //0.4 alpha
    UI7NavBarSytleDark, //0.8 alpha
    UI7NavBarSytleBlack, //1.0
};

@interface TTNavigationController : UINavigationController

- (void)setNavBarBgWithImage:(UIImage *)image;
- (void)setNavBarBgWithColor:(UIColor *)cl;
- (void)setNavBarStyle:(UI7NavBarSytle)style;

@end

.m

#import "TTNavigationController.h"
#import "UIApplication+UI7.h"

@interface TTNavigationController ()
@property (nonatomic,strong)UIImageView *navColorOverly;
@end

@implementation TTNavigationController


- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.navigationBar.opaque = NO;
    if (kCFCoreFoundationVersionNumber>=kCFCoreFoundationVersionNumber_iOS_5_0) {
        NSArray *vs=[self.navigationBar subviews];
        Class clazz;
        if (kCFCoreFoundationVersionNumber>=kCFCoreFoundationVersionNumber_iOS_6_0) {
            clazz=NSClassFromString(@"_UINavigationBarBackground");
        }else{
            clazz=NSClassFromString(@"UINavigationBarBackground");
        }
        for (UIView *v in vs) {
            if ([v isKindOfClass:clazz]) {
                v.hidden=YES;
                break;
            }
        }
    }
    [self setNavBarStyle:UI7NavBarSytleDark];
    [self.navigationBar insertSubview:_navColorOverly atIndex:0];
}



- (UIImageView *)navColorOverly
{
    if (!_navColorOverly) {
        if (!_navColorOverly) {
            _navColorOverly=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.navigationBar.frame.size.width, self.navigationBar.frame.size.height+20)];
            _navColorOverly.frame=CGRectMake(0, -20, self.navigationBar.frame.size.width, 64);
        }
    }
    return _navColorOverly;
}

- (void)setNavBarStyle:(UI7NavBarSytle)style
{
    switch (style) {
        case UI7NavBarSytleLight:
            [self setNavBarBgWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.4]];
            break;
        case UI7NavBarSytleBlack:
            [self setNavBarBgWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1]];
            break;
        default: //UI7NavBarSytleDark:
            [self setNavBarBgWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.8]];
            break;
    }
}

- (void)setNavBarBgWithColor:(UIColor *)cl
{
    UIGraphicsBeginImageContext(CGSizeMake(1, 1));
    [cl set];
    UIRectFill(CGRectMake(0, 0, 1, 1));
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.navColorOverly.image=[image stretchableImageWithLeftCapWidth:1 topCapHeight:1];
}

- (void)setNavBarBgWithImage:(UIImage *)image
{
    self.navColorOverly.image=image;
}

@end
@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {}
@end


step 4接着是刚才提到的,在info.plist里加入UIViewControllerBasedStatusBarAppearance,设为NO



step 5接着就写个Demo试试效果吧。

记得appdelegate的application:didFinishLaunchingWithOptions:里记得调用[UIApplicationinject];作用就是注入状态栏,让其底色透明



简单看下效果(iOS 5,6,7):

 

 

 代码去github取吧,如果写不好不要吐槽··哈哈··

 https://github.com/iBcker/UI7NavigationBar

 


2017-08-04 15:16:00 weixin_30426957 阅读数 13
  • iOS开发-全面解析iOS蓝牙BLE4.0开发

    只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发

    3672 人正在学习 去看看 许英俊

iOS SDK 集成指南

SDK说明

适用版本

本文匹配的 SDK版本:r2.1.5 以后。
查看最近更新了解最新的SDK更新情况。
使用Xcode 6及以上版本可以使用新版Push SDK,Xcode 5环境下需要运行旧版本SDK(1.7.4)

资源文件

包名为JPush-iOS-SDK-{版本号}

  • lib文件夹:包含头文件 JPUSHService.h,静态库文件jpush-ios-x.x.x.a,jcore-ios-x.x.x.a,支持的iOS版本为 6.0 及以上版本。(请注意:模拟器不支持APNs)
  • pdf文件:集成指南
  • demo文件夹:示例

创建应用

  • 在 JPush的管理Portal 上创建应用并上传APNs证书。如果对APNs证书不太了解 请参考: iOS 证书设置指南

jpush_ios

  • 创建成功后自动生成 AppKey 用以标识该应用。

jpush_ios

配置工程

导入SDK

选择1:Cocoapods导入

  • 通过Cocoapods下载地址:
pod 'JPush'
  • 如果需要安装指定版本则使用以下方式(以3.0.2版本为例):
pod 'JPush', '3.0.2'

选择2:手动导入

  • 在极光官网下载最新SDK
  • 将SDK包解压,在Xcode中选择“Add files to 'Your project name'...”,将解压后的lib子文件夹(包含JPUSHService.h、jpush-ios-x.x.x.a、jcore-ios-x.x.x.a)添加到你的工程目录中。
  • 添加Framework
    • CFNetwork.framework
    • CoreFoundation.framework
    • CoreTelephony.framework
    • SystemConfiguration.framework
    • CoreGraphics.framework
    • Foundation.framework
    • UIKit.framework
    • Security.framework
    • libz.tbd (Xcode7以下版本是libz.dylib)
    • AdSupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加)
    • UserNotifications.framework (Xcode8及以上)
    • libresolv.tbd (JPush 2.2.0及以上版本需要, Xcode7以下版本是libresolv.dylib)

注意: 如果集成JPush 3.0.1及以上版本, 且同时集成极光其他SDK(如:JMessage 3.0.0及以上版本) 
1. Cocoapods导入,建议都更新为线上最新版本,来避免Jcore版本不一致导致的冲突。 
2. 手动导入,在工程中只需保留一个最新版本的jcore-ios-x.x.x.a静态库文件。

Build Settings

如果你的工程需要支持小于7.0的iOS系统,请到Build Settings 关闭 bitCode 选项,否则将无法正常编译通过。

  • 设置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夹(默认为lib)与工程文件在同一级目录下,则都设置为"$(SRCROOT)/{静态库所在文件夹名称}"即可。

Capabilities

如使用Xcode8及以上环境开发,请开启Application Target的Capabilities->Push Notifications选项,如图:
jpush_ios

允许Xcode7支持Http传输方法

如果您使用的是2.1.9及以上的版本则不需要配置此步骤
如果用的是Xcode7或更新版本,需要在App项目的plist手动配置下key和值以支持http传输:

选择1:根据域名配置

  • 在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。
  • 然后给它添加一个NSExceptionDomains,类型为字典类型;
  • 把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作为Key,类型为字典类型。
  • 每个域下面需要设置2个属性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads。 两个属性均为Boolean类型,值分别为YES、YES。

如图:

jpush_ios

选择2:全局配置

  <key>NSAppTransportSecurity</key> 
  <dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <true/> 
  </dict>            

添加头文件

请将以下代码添加到 AppDelegate.m 引用头文件的位置。

// 引入JPush功能所需头文件
#import "JPUSHService.h"
// iOS10注册APNs所需头文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
// 如果需要使用idfa功能所需要引入的头文件(可选)
#import <AdSupport/AdSupport.h>

添加Delegate

为AppDelegate添加Delegate。

参考代码:

@interface AppDelegate ()<JPUSHRegisterDelegate>

@end

添加初始化代码

2.1.0版本开始,API类名为JPUSHService,不再使用原先的APService。

添加初始化APNs代码

请将以下代码添加到
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

  //Required
  //notice: 3.0.0及以后版本注册可以这样写,也可以继续用之前的注册方式
  JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
  entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
  if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
    // 可以添加自定义categories
    // NSSet<UNNotificationCategory *> *categories for iOS10 or later
    // NSSet<UIUserNotificationCategory *> *categories for iOS8 and iOS9
  }
  [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];

添加初始化JPush代码

请将以下代码添加到
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

  // Optional
  // 获取IDFA
  // 如需使用IDFA功能请添加此代码并在初始化方法的advertisingIdentifier参数中填写对应值
  NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

  // Required
  // init Push
  // notice: 2.1.5版本的SDK新增的注册方法,改成可上报IDFA,如果没有使用IDFA直接传nil
  // 如需继续使用pushConfig.plist文件声明appKey等配置内容,请依旧使用[JPUSHService setupWithOption:launchOptions]方式初始化。
  [JPUSHService setupWithOption:launchOptions appKey:appKey
                        channel:channel
               apsForProduction:isProduction
          advertisingIdentifier:advertisingId];  
部分参数说明:
  • appKey
    • 填写管理Portal上创建应用后自动生成的AppKey值。请确保应用内配置的 AppKey 与 Portal 上创建应用后生成的 AppKey 一致。
  • channel
    • 指明应用程序包的下载渠道,为方便分渠道统计,具体值由你自行定义,如:App Store。
  • apsForProduction
    • 1.3.1版本新增,用于标识当前应用所使用的APNs证书环境。
    • 0 (默认值)表示采用的是开发证书,1 表示采用生产证书发布应用。
    • 注:此字段的值要与Build Settings的Code Signing配置的证书环境一致。
  • advertisingIdentifier

注册APNs成功并上报DeviceToken

请在AppDelegate.m实现该回调方法并添加回调方法中的代码

- (void)application:(UIApplication *)application 
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

  /// Required - 注册 DeviceToken
  [JPUSHService registerDeviceToken:deviceToken];
}

实现注册APNs失败接口(可选)


- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  //Optional
  NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}

添加处理APNs通知回调方法

请在AppDelegate.m实现该回调方法并添加回调方法中的代码

#pragma mark- JPUSHRegisterDelegate

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
  // Required
  NSDictionary * userInfo = notification.request.content.userInfo;
  if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    [JPUSHService handleRemoteNotification:userInfo];
  }
  completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
  // Required
  NSDictionary * userInfo = response.notification.request.content.userInfo;
  if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    [JPUSHService handleRemoteNotification:userInfo];
  }
  completionHandler();  // 系统要求执行这个方法
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

  // Required, iOS 7 Support
  [JPUSHService handleRemoteNotification:userInfo];
  completionHandler(UIBackgroundFetchResultNewData);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

  // Required,For systems with less than or equal to iOS6
  [JPUSHService handleRemoteNotification:userInfo];
}



添加处理JPush自定义消息回调方法

如需使用JPush的自定义消息功能,请参考文档来实现自定义消息的处理回调方法。

成功运行

真机调试该项目,如果控制台输出以下日志则代表您已经集成成功。

2016-08-19 17:12:12.745823 219b28[1443:286814]  | JPUSH | I - [JPUSHLogin] 
----- login result -----  
uid:5460310207   
registrationID:171976fa8a8620a14a4  

如果调试运行中遇到问题请参考:iOS SDK 调试指南

高级功能

关于IDFA

r2.1.5版本增加一个上传IDFA字符串的接口

 + (void)setupWithOption:(NSDictionary *)launchingOption
                  appKey:(NSString *)appKey
                 channel:(NSString *)channel
        apsForProduction:(BOOL)isProduction
   advertisingIdentifier:(NSString *)advertisingId;

如果不使用IDFA,仍可使用接口

+ (void)setupWithOption:(NSDictionary *)launchingOption
                  appKey:(NSString *)appKey
                 channel:(NSString *)channel
        apsForProduction:(BOOL)isProduction;

JPush SDK 相关事件监听

建议开发者加上API里面提供的以下类型的通知:

extern NSString *const kJPFNetworkIsConnectingNotification; // 正在连接中

extern NSString * const kJPFNetworkDidSetupNotification; // 建立连接

extern NSString * const kJPFNetworkDidCloseNotification; // 关闭连接

extern NSString * const kJPFNetworkDidRegisterNotification; // 注册成功

extern NSString *const kJPFNetworkFailedRegisterNotification; //注册失败

extern NSString * const kJPFNetworkDidLoginNotification; // 登录成功

温馨提示: 

Registration id 需要添加注册kJPFNetworkDidLoginNotification通知的方法里获取,也可以调用[registrationIDCompletionHandler:]方法,通过completionHandler获取

extern NSString * const kJPFNetworkDidReceiveMessageNotification; // 收到自定义消息(非APNs)

其中,kJPFNetworkDidReceiveMessageNotification传递的数据可以通过NSNotification中的userInfo方法获取,包括标题、内容、extras信息等

转载于:https://www.cnblogs.com/shenlaiyaoshi/p/7285299.html

2015-09-19 15:06:00 dingduozi4062 阅读数 5
  • iOS开发-全面解析iOS蓝牙BLE4.0开发

    只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发

    3672 人正在学习 去看看 许英俊

IOS学习之路--OC的基础知识

1.项目经验

2.基础问题

3.指南认识

4.解决思路

 

 

 ios开发三大块:

1.Oc基础

2.CocoaTouch框架

3.Xcode使用

 

--------------------

CocoaTouch

Media

Core Services

Core OS

--------------------

System Framework

 

 

OC的类声明,定义域

 

OC关键字定义为  @class

O-C特有的语句for(。。in 。。)迭代循环,其他的条件和循环语句和c一样

OC对面向对象的概述

1)基类:NSOject

2)一般的继承是单继承,使用协议@protocol 实现多重继承

3)所有的函数都是虚函数

Id类型

OC中每个目标都可以表达为id类型,泛型。可以认为是NSObject *或者 void Nil

  等同于null,表示一个目标指针

类定义

   Oc的类分为2个文件,

   .h文件存放类,函数的声明(声明的关键字 @interfance   @end)

   .m文件存放类的具体实现(实现关键字)

对象和类的方法

“+” 表示类的方法

-”表示对象的方法  -(int)返回值f 函数的名字: (int)  x;参数(有个“:”表示有几个参数,从第二个参数起“:”前面必须加空格)

对于方法声明的讲解

“:”表示继承 @interface  Dog : NSObject{}  @end

“{}”之间只能写字段(如:int age),不能写函数

右括号和@end间接写的是函数

创建对象

  Dog *dog=[Dog alloc] ;  一个类的名字 + alloc

初始化构造函数

   [dog init];    凡是以init…开头的都是构造函数

销毁对象

[dog release];

字段定义

三种作用域:@public @protected(保护,在类本身或者子类中) @private (只能在类的内部)

补充:缺省的是protected

函数全部用public

变量必须定义在类{}之间的地方

注:在c中函数和字段是可以重名的

类的声明

  必须带“*” 即表示指针也表示引用   Dog(对象) * myDog (变量名)

访问 myDog.dog(变量名访问字段)或者使用空格       

多参数方法

 带两个参数(函数名为f::)

  两种写法  -(float)f(int)x 【空格】 :(int)y           不提倡这种写法

2)-(float)f(int)x  【空格】g:(int)y  g:表示标签   (第一参数不能有标签,第一个函数名就相当于第一个参数的标签,是为了方便阅读)

如何调用方法

无参数

-(int)foo;

  Int ret=[obj foo] 调obj的方法,没有参数,调方法的时候用[]

一个参数

-(int)foo:(int)a;

Int ret=[obj foo:10]

带标签

-(int)foo:(int)a   andB(int)b;

Int ret=[obj foo:10  andB:2];

OC不是严格的函数重载

-(int)g:(int)x;

-(int)g:(folat)x;两个函数的函数名都为”g:” 在OC中是错误的,但是c中是可行  

函数作用域声明

.h中定义的所有函数都是public类型的

私有化的解决方法

.m文件中使用Categories

 

@property  age

合成定义在.h文件中使用  编译器

=(1)”-(void)setAge:(int)newAge;” + “-(int) age;”

@synthesize  合成实现,编译器自动实现getter和setter函数

 =(1)”-(void)setAge:(int)newAge{ age = newAge;}”+”return age;”

属性可以是

readwrite(缺省),readonl:

表示可读写(setter和getter函数都可以使用),readonly只能用getter

assign(缺省)retain,copy

表示属性如何存储  assign相当于“=”表示赋值

Nonatomic(UI中常用)

表示不用考虑线程安全问题

getter=…,setter=…

重新设置getter函数和setter函数名

 

点语法

 

内部类age和点age(.age)不同

直接访问age相当于访问age字段,

.age在等号左边相当于setter函数,在等号的右边相当于getter函数

例子:dog.age=200;展开成[dog setAge:200]; 

 

说明:

1)age不是变量的名字,而是函数

2)点语法在等号的左边表示设置函数(set…)

dogAge = dog.age;展开成 dogAge = [dog age];  (系统自动展开)

 

@class 与 #import :

import会包含这个类的所有信息,包括实体变量和方法,

而@class只是告诉编译器,其后面声明的名称是类的名称

 

在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,

所以在头文件中一般使用@class来声明这个名称是类的名称。

 

而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,

所以需要使用#import来包含这个被引用类的头文件。

 

在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,

如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,

如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。

 

如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,

如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。

 

所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。

在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.

 

 

字符串

 

NSString: Cocoa中处理字符串的类

NSString型数据是特殊的NSString字面量,其指示标志是双引号内的字符串前的@,如@“Hi!”

NSString的stringWithFormat:方法就是通过格式字符串和参数来创建NSString的

+(id)stringWithFormat:(NSString *)format,...;

例子:

NSString *height;

Height=[NSString stringWithFormat:@”Your height is %d feet,%d inches”,5,11];

stringWithForat:(1)定义最后的省略号:可以接受对个以逗号隔开的其他参数

2)“+”修饰的方法,为类方法,这个方法属于类对象(而不是类的实例对象)并且通常用于创建新的实例

是一个工厂方法,根据提供的参数创建新对象

-”创建的大部分方法都是实例方法

NSString的实例方法length。返回的是字符串中的字符个数

使用 -(unsigned int)length:

    Unsigned int length=[height length];

If([height length]>35){

NSLog(@”wow,you’re relly  tall!”)}

比较字符串               

      isEqualToString:可以用来比较接收方和当做参数传递来的字符串。返回一个BOOL型数据表示字符串的内容是否相同,

-(BOOL)isEqualToString:(NSString *)aString;

具体的使用方法:

NSString *thing1=@“hello 5”;

NSString *thing2;

Thing2=[NSString stringWithFormat:@“hello %d”,5];

If([thing1 isEqualToString:thing2]){ NSLog(@”They are  the same!);

注意:“==“运算符只判断thing1和thing2的这真数值,而不是他们所指的对象

两个字符串是否相等(等价性,两个字符串是否代表同一个事物)用isEqualToString

Compare:(区分大小写的比较的字符逐个字符的进行比较,,返回一个NSComparisonResult(就是一个enum型数据)来显示比较结果。如返回值是NSOrderedAscending,那么左侧的数值就小右侧的数值,即compare的目标在字母表中的排序位置比传递进来的字符串更靠前

Compare:options:

例子:-(NScomparisonResult)compare:(NSString *)string

                           options:(unsigned)mask;

options参数是一个位掩码。可以使用位或(bitiwise-OR)运算符(|)来添加选项标记。常用的选项如下:

NSCaseInsensitiveSearch:不区分大小写字符

NSLiteralSearch:进行完全比较,区分大小写

NSNumericSearch:比较字符串的字符个数,而不是字符值,

可变数组

NSString一样NSArray创建的是不可变对象的数组。补充类NSMutableArray,可以随意的田间和删除数组,通过类方法arrayWithCapacity来创建新的可变数组

+(id)arrayWithCapacity:(unsignde)numltems

删除特定索引处德对象。removeObject

 

枚举

NSEnumerator是Cocoa用来描述集合迭代运算的方式,需通过objectEnumerator像组组请求枚举器

-(NSEnumerator *)objcetEnumerator

从后向前浏览集合 reverseObjectEnumerator

可以用while循环,每次循环都向枚举器请求他的nextObject(下一个对象)

-(id)nextObject;返回nil时,循环结束

注:不能通过添加或删除对象这类方式来改变

 

 

字典:NSDictionary(也成为散列表或关联类表)使用的是键查询的优化存储方式

就是关键字及其定义的集合

NSDictionary在给定的关键字(通常是一个NSString字符串)下存储一个数值(可以是任何类型的对象

NSString和NSArray一样只能使用NSMutableDictionary添加或者删除

创建字典dictionaryWithObjectsAndKeys;

    +(id)dictionaryWithObjectsAndKeys:

          (id)firstObject,…;

objectForKey:获取字典中得值,向方法传递之前用来存储改制的关键字

  -(id)objectForKey:(id)aKey;

添加元素

-(void)setObject:forkey

 

NSNumber类来包装(即以对象形式实现)基本数据类型:

创建NSNumber对象:

+(NSNumber *)numberWithChar:(char)  value;

+(NSNumber *)numberWithint:(int)value;

+(NSNumber *)numberWithFolatr (float) value;

+(NSNumber *)numberWithBOOL  (BOOL) value;

 

 

对初学者来说,Objective-C存在了很多令人费解的写法,实际上他们是非常优雅的。

程序员写的最多的就是函数以及调用自己写的或者别人写的函数。本文就从函数的角度来看下Objective-C的优雅之处。

C#和Objective-C同属于c系列语言。让我们先看下C#的函数定义和调用,做个对比。

C#函数的定义:

  1. public void doIt(string actorName, string movieName, int timesSeen)  
  2.         {  
  3.             Console.Write("{0} is my favorite actor in the movie {1}, I saw it {2} times.", actorName, movieName, timesSeen);  
  4.         } 

函数的调用:

  1. Class1 objMovie = new Class1();  
  2.             objMovie.doIt("莱昂纳多·迪卡普里奥", "盗梦空间", 120); 

在让.net程序员看下Objective-C的定义:

  1. - (void) doIt:(NSString *) actorName movieName: (NSString*) value timesSeen: (int)times {  
  2.                 NSLog(@"%@ is my favorite actor in the movie %@, I saw it %i times.",actorName, value, times);  
  3.           } 

如果你第一次看Objective-C,肯定会琢磨不透上面的代码,怀疑是不是写错了。

对于上面这个函数的定义:

1、'-'表示这个函数是实例函数(类似非静态函数),'+'表示这个函数是类函数(类似静态函数)

2、(void)表示这个函数没有返回值。

3、函数名是'doIt:',而不是'doIt'

4、参数用空格隔开

5、参数类型写在括号中

6、参数分内部参数和外部参数,如电影名称,内部参数是:value,外部参数是:movieName

参数

7、函数的一个参数没有外部参数的名称,有内部参数名。如:actorName。

调用:

调用

从上面代码可以看出除了第一个参数,其余的参数都可以加上外部参数名称用于区别。

从上面可以看出Objective-C和C#区别很大,实在会令.net程序员费解。Objective-C函数设计的优雅之处在于即有内部参数名又有外部参数名,可以不用在再内部定义变量来存放函数的参数。

对Objective-C函数学习的一个简单总结。

 

 

  • 运行过程

1.编写OC程序:.m源文件

2.编译.m文件为.o目标文件:cc -c xxxx.m

3.链接.o文件为a.out可执行文件:cc xxxx.o -framework Foundation

4.执行a.out文件:./a.out

  • #import 的功能跟#include一样,只是更好用,他避免了头文件的多次包含
  • 为了能使用OC的特性, 一定要引入#import <Foundation/Foundation.h>
  •  类定义// @implementation 和 @end

 

复制代码
复制代码
// 设计(定义)一个车类
// @implementation 和 @end
// : NSObject :让Car这个类具备创建对象的能力(继承)
@implementation Car : NSObject
// 这个大括号里面只能写所有的属性
{
    // @public:让对象的属性可以被外面的指针访问,默认是私有的
    @public
    int wheels; // 默认基本数据类型的初始值都是0
}

// 在@end的前面,大括号{}外面写行为
// 给Car对象增加一个行为(方法)
// 给对象增加一个行为,必须以减号 - 开头, 给类增加一个对象是+。
// OC方法中的小括号()只是主要扩住类型
- (void) run
{
    // 访问车子对象内部的属性,直接用属性名就可以
    NSLog(@"%i个轮子,%f时速的车子跑起来了!", wheels, speed);
}
+ (Void) test
{
    // 这是类方法。上面那个-号的是对象方法。
}

@end
复制代码
复制代码

 

 

 

  •  类调用
复制代码
复制代码
    // 在OC中想执行一些行为,首先写个 [行为执行者  行为名称]
    
    // new这个行为执行完毕后,会返回这个对象的地址
    Car *c = [Car new];
    // 给c指向的车子对象的wheels属性赋值
    c->wheels = 4; // 等价于 (*c).wheels = 4
    
    // 给指针变量c指向的对象“发送”一条run消息,让这个对象执行run这个行为
    [c run];
复制代码
复制代码
  •  声明&实现
复制代码
复制代码
// 声明一个类
/*
 1.类名
 2.继承了NSObject
 3.声明属性
 4.声明方法(仅仅是声明,不需要实现)
 5.实现和声明中的成员变量不能同名
 */
@interface Book : NSObject
{  
    @public
    double price;// 这些属性称为对象的“成员变量”
}

// 声明一个方法(行为)
- (void)reng;

@end
复制代码
复制代码
复制代码
复制代码
// 定义(实现)一个类
/*
 只用来实现@interface中声明的方法
 */
@implementation Book 

- (void)reng
{
    NSLog(@"%f的书被扔了!", price);
}
复制代码
复制代码
  •  多参数的声明和使用
复制代码
复制代码
- (void) fly
{
    NSLog(@"i can fly, my age is %d", age);
}

// 一个参数对应一个冒号
// 冒号也是方法名的一部分
- (void)fly:(int)howHeight
{
    NSLog(@"i can fly, my age is %d, my height %d", age, howHeight);
}

// 多个参数的情况。  withTime是方法名的一部分.times是参数名称
- (void)fly:(int)howHeight :WithTime(int)times
{
}
复制代码
复制代码
    Person *p = [Person new];
    [p fly];
    [p fly:99];
    [p fly:99 WithTime:10];
  •  OC对象方法和函数的区别

  1. 函数属于整个文件,在文件的任意地方都能调用;对象的方法只属于这个对象,只有对象才能调用

  2. 对象的方法只能声明在@infterface 和@end 之间,对象方法只能实现在@implementation 和@end之间。

   函数的声明和定义可以写在任意地方,函数不能归某个类所有,只属于某个文件。

  • 消息机制

  给指针变量所指向的对象发送一条消息(消息名称就是方法名),让那个对象执行相应的方法(动态)

 

 

 

iOS求职之OC面试题

1、Objective-C的类可以多重继承么?可以采用多个协议么?

答:不可以多重继承,可以采用多个协议。

2、#import和#include的区别是什么?#import<> 跟 #import""有什么区别?

#import能避免头文件被重复包含的问题:

1) 一般来说,导入objective c的头文件时用#import,包含c/c++头文件时用#include。

使用include要注意重复引用的问题:

class A,class B都引用了class C,class D若引用class A与class B,就会报重复引用的错误。

2)#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。

所以,#import比起#include的好处就是它避免了重复引用的问题。所以在OC中我们基本用的都是import。

#import<> 包含iOS框架类库里的类,#import""包含项目里自定义的类。

 

3、Category是什么?扩展一个类的方式用继承好还是类目好?为什么?

答:Category是类目。用类目好,因为继承要满足a is a b的关系,而类目只需要满足a has a b的关系,局限性更小,你不用定义子类就能扩展一个类的功能,还能将类的定义分开放在不同的源文件里, 用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。

 

4、延展是什么?作用是什么?

答:延展(extension):在自己类的实现文件中添加类目来声明私有方法。

5、类实例(成员)变量的@protected,@private,@public声明各有什么含义?

@protected:受保护的,该实例变量只能在该类和其子类内访问,其他类内不能访问。

@private:私有的,该实例变量只能在该类内访问,其他类内不能访问。

@public:共有的,该实例变量谁都可以访问。

6、id声明的对象有什么特性?

Ø  没有 * 号

Ø  动态数据类型

Ø  可以指向任何类的对象(设置是nil),而不关心其具体类型

Ø  在运行时检查其具体类型

Ø  可以对其发送任何(存在的)消息

7、委托是什么?委托和委托方双方的property声明用什么属性?为什么?

委托:一个对象保存另外一个对象的引用,被引用的对象实现了事先确定的协议,该协议用于将引用对象中的变化通知给被引用对象。

委托和委托方双方的property声明属性都是assign而不是retain

为了避免循环引用造成的内存泄露。

      循环引用的问题这样理解:

       比如在main函数中创建了两个类的对象A和B,现在引用计数都是1。现在让A和B互相引用(A有一个属性是B对象,属性说明是retain;B有一个属性是A对象,属性说明是retain),现在两个对象的引用计数都增加了1,都变成了2。

  现在执行[A release]; [B release]; 此时创建对象的main函数已经释放了自己对对象的所有权,但是此时A和B的引用计数都还是1,因为他们互相引用了。

  这时你发现A和B将无法释放,因为要想释放A必须先释放B,在B的dealloc方法中再释放A。同理,要想释放B必须先释放A,在A的dealloc方法中再释放B。所以这两个对象将一直存在在内存中而不释放。这就是所谓的循环引用的问题。要想解决这个问题,一般的方法可以将引用的属性设置为assign,而不是retain来处理。

8、浅拷贝和深拷贝区别是什么?

       浅层复制:只复制指向对象的指针,而不复制引用对象本身。

深层复制:复制引用对象本身。

意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的只不过是是一个指针,对象本身资源还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了两份独立对象本身。

用网上一哥们通俗的话将就是:

浅复制好比你和你的影子,你完蛋,你的影子也完蛋

深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。

9、内存管理的几条原则是什么?按照默认法则,哪些关键字生成的对象需要手动释放?哪些情况下不需要手动释放,会直接进入自动释放池?

•       当使用new、alloc或copy方法创建一个对象时,该对象引用计数器为1。如果不需要使用该对象,可以向其发送release或autorelease消息,在其使用完毕时被销毁。

•       如果通过其他方法获取一个对象,则可以假设这个对象引用计数为1,并且被设置为autorelease,不需要对该对象进行清理,如果确实需要retain这个对象,则需要使用完毕后release。

•       如果retain了某个对象,需要release或autorelease该对象,保持retain方法和release方法使用次数相等。

 

使用new、alloc、copy关键字生成的对象和retain了的对象需要手动释放。设置为autorelease的对象不需要手动释放,会直接进入自动释放池。

 

10、怎样实现一个单例模式的类,给出思路,不写代码。

•       首先必须创建一个全局实例,通常存放在一个全局变量中,此全局变量设置为nil

•       提供工厂方法对该全局实例进行访问,检查该变量是否为nil,如果nil就创建一个新的实例,最后返回全局实例

•       全局变量的初始化在第一次调用工厂方法时会在+allocWithZone:中进行,所以需要重写该方法,防止通过标准的alloc方式创建新的实例

•       为了防止通过copy方法得到新的实例,需要实现-copyWithZone方法

•       只需在此方法中返回本身对象即可,引用计数也不需要进行改变,因为单例模式下的对象是不允许销毁的,所以也就不用保留

•       因为全局实例不允许释放,所以retain,release,autorelease方法均需重写

11、@class的作用是什么?

答:在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。

•       @class的作用是告诉编译器,有这么一个类,用吧,没有问题

•       @class还可以解决循环依赖的问题,例如A.h导入了B.h,而B.h导入了A.h,每一个头文件的编译都要让对象先编译成功才行

•       使用@class就可以避免这种情况的发生

12、KVC是什么?KVO是什么?有什么特点?

•       KVC是键值编码,特点是通过指定表示要访问的属性名字的字符串标识符,可以进行类的属性读取和设置

•       KVO是键值观察,特点是利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知

13、MVC是什么?有什么特性?

–      MVC是一种设计模式,由模型、视图、控制器3部分组成。

–      模型:保存应用程序数据的类,处理业务逻辑的类

–      视图:窗口,控件和其他用户能看到的并且能交互的元素

–      控制器:将模型和试图绑定在一起,确定如何处理用户输入的类

14、定义属性时,什么情况使用copy、assign、retain?

使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float,double, char, 等等)

使用copy: 希望获得源对象的副本而不改变源对象内容时,对NSString

使用retain: 希望获得源对象的所有权时,对其他NSObject和其子类

 

15.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?

assign用于简单数据类型,如NSInteger,double,bool,

retain和copy用于对象,

readwrite是可读可写特性;需要生成getter方法和setter方法时

readonly是只读特性  只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变

assign是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;

retain表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;

copy表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。

nonatomic非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic

 

16.id 声明的对象有什么特性?

答:Id声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c的对象;

 

17.Objective-C如何对内存管理的,说说你的看法和解决方法?

答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。

 

18.内存管理的几条原则时什么?

谁申请,谁释放

遵循Cocoa Touch的使用原则;

内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,一定要用对特性关键字,对于“内存泄漏”,一定要申请了要负责释放,要细心。

 

19.那些关键字生成的对象 需要手动释放?

答:关键字alloc 或new 生成的对象需要手动释放

 

20在和property结合的时候怎样有效的避免内存泄露?

答:设置正确的property属性,对于retain需要在合适的地方释放

 

21.如何对iOS设备进行性能测试?

Profile-> Instruments ->Time Profiler

22.Object-c的类可以多重继承么?可以实现多个接口么?

答:Object-c的类不可以多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;

 

23.Category是什么?重写一个类的方式用继承好还是分类好?为什么?

答:Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。

 

24.描述一下iOS SDK中如何实现MVC的开发模式

MVC是模型、试图、控制开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图控制层来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是控制层,由它负责控制视图,访问模型数据

 

25. Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?

线程创建有三种方法:使用NSThread创建、使用 GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是 performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone

 

26、iPhone5 的屏幕分辨率大小为  1136* 640  ?

答:屏幕分辨率:用于量度位图图像内数据量多少的一个参数。通常表示成ppi(每英寸像素Pixel per inch)。屏幕物理尺寸不变,分辨率越高,每单位面积内包含的细节(像素点)越多。

 

27、struct strA {      int a;     float b;   char c;  } expA;       

   printf("%ld",sizeof(expA));     输出结果为  12  ?

       该问题涉及编译器的“内存对齐”问题:

现代计算机中内存空间都是按照byte(字节)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。

通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。

但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。

       对于结构体来说,按成员中所占字节最大的是float类型,占用4个字节,一共有3个成员,所以总的占用字节为:4* 3 = 12.

       可通过编译器命令来设定:

      #progma pack (2)   

 

28、@property语法中readonly/readwrite,atomic/nonatomic的作用,@dynamic的作用?

      @Property:Objective-C语言关键词,与@synthesize配对使用。xcode4.5以及以后的版本,@synthesize可以省略。

功能:让编译器自动编写一对与数据成员同名的方法声明来省去读写方法的声明。

声明property的语法为:

@property (参数1,参数2) 类型 名字;

如:@property(nonatomic,retain) UIWindow *window;

 

其中参数主要分为三类:

读写属性: (readwrite/readonly)

setter语意:(assign/retain/copy)

原子性: (atomicity/nonatomic)

 

各参数意义如下:

readwrite:同时产生setter\getter方法

readonly:只产生简单的getter,没有setter。

 

assign:默认类型,setter方法直接赋值,而不进行retain操作

retain:setter方法对参数进行release旧值,再retain新值。

copy:setter方法进行Copy操作,与retain一样

 

atomic:原子性,它没有一个如果你没有对原子性进行一个声明(atomic or nonatomic),那么系统会默认你选择的是atomic。

原子性就是说一个操作不可以被中途cpu暂停然后调度, 即不能被中断, 要不就执行完, 要不就不执行. 如果一个操作是原子性的,那么在多线程环境下, 就不会出现变量被修改等奇怪的问题。原子操作就是不可再分的操作,在多线程程序中原子操作是一个非常重要的概念,它常常用来实现一些同步机制,同时也是一些常见的多线程Bug的源头。当然,原子性的变量在执行效率上要低些。

关于异步与同步:并非同步就是不好,我们通常需要同时进行多个操作,这时使用异步,而对于程序来说,一般就是使用多线程,然而我们很多时候需要在多个线程间访问共享的数据,这个时候又需要同步来保证数据的准确性或访问的先后次序。当有多个线程需要访问到同一个数据时,OC中,我们可以使用@synchronized(变量)来对该变量进行加锁(加锁的目的常常是为了同步或保证原子操作)。

nonatomic:非原子性,是直接从内存中取数值,因为它是从内存中取得数据,它并没有一个加锁的保护来用于cpu中的寄存器计算Value,它只是单纯的从内存地址中,当前的内存存储的数据结果来进行使用。在多线环境下可提高性能,但无法保证数据同步。

 

29、OSI(Open System Interconnection)开放式系统互联参考模型 把网络协议从逻辑上分为了7层,试列举常见的应用层协议。

       注意问的是应用层协议,有些同学直接答了七层模型。

       在开放系统互连(OSI)模型中的最高层,为应用程序提供服务以保证通信,但不是进行通信的应用程序本身。

Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。

FTP文件传输协议是TCP/IP网络上两台计算机传送文件的协议,FTP是在TCP/IP网络和INTERNET上最早使用的协议之一,它属于网络协议组的应用层。

 

超文本传输协议 (HTTP-Hypertext transfer protocol) 是分布式,协作式,超媒体系统应用之间的通信协议。是万维网(world wide web)交换信息的基础。

SMTP(Simple MailTransfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式,它帮助每台计算机在发送或中转信件时找到下一个目的地。

时间协议(TIME protocol)是一个在RFC 868内定义的网络协议。它用作提供机器可读的日期时间资讯。

DNS 是域名系统 (Domain NameSystem) 的缩写,是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库。

SNMP(Simple Network ManagementProtocol,简单网络管理协议)的前身是简单网关监控协议(SGMP),用来对通信线路进行管理。

TFTP(Trivial FileTransfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。

 

30、网络传输层协议中,基于TCP/IP协议和UDP/IP的连接有什么区别?

TCP:TransmissionControl Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified)。

UDP 是User DatagramProtocol的简称, 中文名是用户数据包协议,是OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。

 

面向连接:是指通信双方在通信时,要事先建立一条通信线路,其有三个过程:建立连接、使用连接和释放连接。电话系统是一个面向连接的模式,拨号、通话、挂机;TCP协议就是一种面向连接的协议。

面向无连接:是指通信双方不需要事先建立一条通信线路,而是把每个带有目的地址的包(报文分组)送到线路上,由系统自主选定路线进行传输。邮政系统是一个无连接的模式,天罗地网式的选择路线,天女散花式的传播形式;IP、UDP协议就是一种无连接协议。

 

31、简述MVC模式中M、V、C分别指代什么及发挥的作用?

MVC开始是存在于Desktop(桌面)程序中的,M是指数据模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。

 

视图是用户看到并与之交互的界面,视图没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。

 

模型表示企业数据和业务规则,模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

 

控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

 

 

32、声明@property的语法中,retain、copy、assign的含义及作用?试写出 @property中带retain和assign关键字,通过@synthesize自动生成的的合成存取方法(set、get方法)的实现代码。

 

getter分析:

@property (nonatomic, retain) test*aTest;

@property (nonatomic, copy) test*aTest;

等效代码:

-(void)aTest {

    return aTest;

}

 

========== 貌似我是分割线 ===========

@property (retain) test* aTest;

@property (copy) test* aTest;

等效代码:

-(void)aTest

{

    [aTest  retain];

    return [aTest  autorelease];

}

 

setter分析:

@property (nonatomic, retain) test*aTest;

@property (retain) test* aTest;

等效于:

-(void)setaTest:(test *)newaTest {

    if (aTest !=newaTest) {

       [aTest  release];

       aTest = [newaTest  retain];

    }

}

========== 貌似我是分割线 ===========

@property (nonatomic, copy) test*aTest;

@property (copy) test* aTest;

等效于:

-(void)setaTest:(test *)newaTest {

    if (aTest != newaTest){

       [aTest  release];

       aTest = [newaTest  copy];

    }

}

 

33、iOS中有哪些回调机制,并作简单的比较。

各种回调机制的比较:

1)目标动作对:当两个对象之间有比较紧密的关系时,如视图控制器与其下的某个视图。

 

2)代理:也叫委托,当某个对象收到多个事件,并要求同一个对象来处理所有事件时。委托机制依赖于某个协议定义的方法来发送消息。

 

3)通告机制:当需要多个对象或两个无关对象处理同一个事件时。

 

4)Block:适用于回调只发生一次的简单任务。

 

34、列出在编码中哪些编码习惯有助于提高代码质量、软件性能和健壮性,减少程序崩溃。

#使用严格的命名规则(如匈牙利命名法)能够避免不必要的类型转换错误。

#在编码前先设计好流程图或使用伪代码,清晰化整个设计意图。

#对自己的代码进行严格的单元测试(unit testing)。

单元测试是指对软件中的最小可测试单元进行检查和验证。如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

#异常的处理

首先不要轻易使用异常的捕获,其次要尽可能捕获具体的异常。对于异常的处理最好能够采用封装的方式,大家统一使用。这样可以保证异常处理的一致性也可以保证当异常出现时性能的稳定。

# 使用内省的方法检查方法的输入

#采用增量式的编程方式。

采用增量式编程和测试,会倾向于创建更小的方法和更具内聚性的类。你应该经常评估代码质量,并不时的进行许多小调整,而不是一次修改许多东西。在写了几行代码之后,就应该进行一次构建/测试。在没有得到反馈时,你不要走的太远。

 

#使用工具(如Instrument)来帮助检查内存泄漏、过早释放内存、CPU使用效率等问题。

#消除所有的编译警告,警告就是错误。

#写防御性的代码,使用内省的方法检查传入的参数。

 

35、JSON中{ }代表_____,[ ]代表_____,试将下面的JSON串用OC对象表示出来:

{ "people": [

{ "firstName": "Brett","lastName":"McLaughlin", "email":"aaaa" },

{ "firstName": "Jason","lastName":"Hunter", "email": "bbbb"},

{ "firstName": "Elliotte","lastName":"Harold", "email": "cccc" }

],

 “location”:”中华人民共和国”

}

 

JSON中{ }代表对象,数据结构为{key1:value1, key2:value2, key3:…… }

[ ]代表数组,与其他语言中的数组类似。

//

@interface People: NSObject

 

@property(nonatomic, copy) NSString* strFirstName;

@property(nonatomic, copy) NSString* strLastName;

@property(nonatomic, copy) NSString* strEmail;

 

@end

 

//

@interfaceJSonData : NSObject

 

@property(nonatomic, retain) NSMutableArray* arrPeople;  // 存放People对象

@property(nonatomic, copy) NSString* strLocation;

 

@end

 

36.  Object-C有多继承吗?没有的话用什么代替?

答:没有,cocoa 中所有的类都是NSObject 的子类,多继承在这里是用protocol 委托代理来实现的
 ,ood的多态特性在obj-c中通过委托来实现。

 

37.bject-C有私有方法吗?私有变量呢?

objective-c – 类里面的方法只有两种, 静态方法和实例方法.

在类里面声名一个私有方法
@interface Controller : NSObject

{ NSString *something;

}
+ (void)thisIsAStaticMethod;
–(void)thisIsAnInstanceMethod;
@end
@interface Controller

(private)

-(void)thisIsAPrivateMethod;
@end

@private可以用来修饰私有变量
在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的

 

38.  堆和栈的区别?

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

申请大小:栈:栈是向低地址扩展的数据结构,是一块连续的内存的区域

                   堆:是向高地址扩展的数据结构,是不连续的内存区域。

分配方式:堆都是动态分配的 ,动态分配由alloca函数进行分配 

                   栈的动态分配由编译器进行释放,无需我们手工实现 

39. kvc和kvo的区别?

kvc:键值编码,是一种间接访问对象的属性,使用字符串来标示属性

kvo:键值观察机制,提供了观察某一属性变化的方法

 

40. 线程和进程的区别?

答:主要不同的是操作系统资源管理方式

线程是一个进程中不同的执行路径,线程有自己的堆、局部变量

进程有独立的地址空间,一个线程死掉,整个进程就会死掉

 

41.  #import和#include的区别,@class代表什么?

答:@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
而#import比起#include的好处就是不会引起重复包含。

 

42. 类别的作用?

答:有时我们需要在一个已经定义好的类中增加一些方法,而不想去重写该类。可以使用类别对该类扩充新的方法。

注意:类别只能扩充方法,而不能扩充成员变量。

   代理的作用

委托代理(degegate),目的是改变和传递控制链

    顾名思义,把某个对象要做的事情委托给别的对象去做。那么别的对象就是这个对象的代理,代替它来打理要做的事。反映到程序中,首先要明确一个对象的委托方是哪个对象,委托所做的内容是什么。

委托机制是一种设计模式。

多态:子类的指针可以赋值给父类

 

43.链表和数组的区别在哪里?

二者都属于一种数据结构

从逻辑结构来看

1. 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费;数组可以根据下标直接存取。

2. 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项,非常繁琐)链表必须根据next指针找到下一个元素

从内存存储来看

1. (静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小

2. 链表从堆中分配空间, 自由度大但是申请管理比较麻烦

 

从上面的比较可以看出,如果需要快速访问数据,很少或不插入和删除元素,就应该用数组;相反, 如果需要经常插入和删除元素就需要用链表数据结构了。

 

 

44. main()

 { int a[5]={1,2,3,4,5};   

   int *ptr=(int *)(&a+1);   

  printf("%d,%d",*(a+1),*(ptr-1));

}

答:2,5   *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5   

&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)   

    int *ptr=(int *)(&a+1);则ptr实际是&(a[5]),也就是a+5

原因如下:&a是数组指针,其类型为 int (*)[5];

   而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同。  

   a是长度为5的int数组指针,所以要加 5*sizeof(int),所以ptr实际是a[5],

   但是prt与(&a+1)类型是不一样的(这点很重要),所以prt-1只会减去sizeof(int*)  

    a,&a的地址是一样的,但意思不一样    

    a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,         a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].

 

45. 写一个委托的interface

@protocol MyDelegate;

@interface MyClass: NSObject

{    id <MyDelegate> delegate; }

//委托方法@protocol MyDelegate- (void)didJobs:(NSArray *)args;

@end

 

46. 写一个NSString类的实现

+(id)initWithCString:(const char *)nullTerminatedCStringencoding:(NSStringEncoding)encoding;

+ (id)stringWithCString: (const char*)nullTerminatedCString             encoding: (NSStringEncoding)encoding

 {   NSString *obj; 

     obj = [selfallocWithZone: NSDefaultMallocZone()];  

     obj = [objinitWithCString: nullTerminatedCString encoding: encoding];  

     returnAUTORELEASE(obj);

}

 

47. 关键字const有什么含意?修饰类呢?static的作用,用于类呢?还有extern c的作用

const意味着"只读",下面的声明都是什么意思? 

const int a; 

int const a; 

const int *a; 

int * const a; 

int const * a const;

前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。

结论:·;关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果 你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清 理的。)  ·; 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。  ·; 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。 

(1)欲阻止一个变量被改变,可以使用 const 关键字。在定义该 const 变量时,通常需要对它进行初 始化,因为以后就没有机会再去改变它了;(2)对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 const,或二者同时指 定为 const;

(3)在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值; (4)对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不能修改类的成员变量; (5)对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返回值不为“左值”。

关键字volatile有什么含意?并给出三个不同的例子。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 

· ;并行设备的硬件寄存器(如:状态寄存器) 

· ; 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

· ; 多线程应用中被几个任务共享的变量

· ;一个参数既可以是const还可以是volatile吗?解释为什么。 

· ; 一个指针可以是volatile 吗?解释为什么。 

下面是答案: 

· ; 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 

·; 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 

static关键字的作用:

(1)函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值; (2)在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

(3)在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明 它的模块内;

(4)在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

(5)在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。

 

extern "C"的作用:

(1)被 extern "C"限定的函数或变量是 extern 类型的;     

 extern是 C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。

(2)被 extern "C"修饰的变量和函数是按照 C 语言方式编译和连接的;

 

extern "C"的惯用法

(1)在 C++中引用 C 语言中的函数和变量,在包含 C 语言头文件(假设为 cExample.h)时,需进 行下列处理:

 extern "C"  { #include "cExample.h"   } 

而在 C语言的头文件中,对其外部函数只能指定为 extern 类型,C语言中不支持 extern "C"声明, 在.c 文件中包含了 extern "C"时会出现编译语法错误。

(2)在 C 中引用 C++语言中的函数和变量时,C++的头文件需添加 extern "C",但是在 C 语言中不 能直接引用声明了 extern "C"的该头文件,应该仅将 C 文件中将 C++中定义的extern "C"函数声明为 extern 类型。

 

48.为什么标准头文件都有类似以下的结构?  

 #ifndef __INCvxWorksh    

   #define __INCvxWorksh    

    #ifdef __cplusplus   

    extern "C" {    

     #endif     /*...*/   

      #ifdef __cplusplus    

      }   

  #endif   

  #endif /* __INCvxWorksh */

显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止该头文件被重复引用。

 

49. #import跟#include的区别,@class呢?

@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import而#import比起#include的好处就是不会引起交叉编译。

 

50.线程与进程的区别和联系?

答:进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。

程和线程的主要差别在于它们是不同的操作系统资源管理方式。

进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。

线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

 

51.列举几种进程的同步机制,并比较其优缺点。

答案:原子操作、信号量机制、自旋锁、管程、会合、分布式系统

进程之间通信的途径

答案:共享存储系统消息传递系统管道:以文件系统为基础

进程死锁的原因

答案:资源竞争及进程推进顺序非法

死锁的4个必要条件

答案:互斥、请求保持、不可剥夺、环路

死锁的处理

答案:鸵鸟策略、预防策略、避免策略、检测与解除死锁

 

52.什么是键-值,键路径是什么

答:模型的性质是通过一个简单的键(通常是个字符串)来指定的。视图和控制器通过键来查找相应的属性值。在一个给定的实体中,同一个属性的所有值具有相同的数据类型。键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。

键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的性质是由先前的性质决定的,接下来每个键的值也是相对于其前面的性质。键路径使您可以以独立于模型实现的方式指定相关对象的性质。通过键路径,您可以指定对象图中的一个任意深度的路径,使其指向相关对象的特定属性。

For example, the keypath address.streetwould get the value of the address property from thereceivingobject, and then determine the street property relative to the addressobject.

 

53.c和obj-c如何混用

1)obj-c的编译器处理后缀为m的文件时,可以识别obj-c和c的代码,处理mm文件可以识别obj-c,c,c++代码,但cpp文件必须只能用c/c++代码,而且cpp文件include的头文件中,也不能出现obj-c的代码,因为cpp只是cpp

2) 在mm文件中混用cpp直接使用即可,所以obj-c混cpp不是问题

3)在cpp中混用obj-c其实就是使用obj-c编写的模块是我们想要的。 如果模块以类实现,那么要按照cpp class的标准写类的定义,头文件中不能出现obj-c的东西,包括#import cocoa的。实现文件中,即类的实现代码中可以使用obj-c的东西,可以import,只是后缀是mm。 如果模块以函数实现,那么头文件要按c的格式声明函数,实现文件中,c++函数内部可以用obj-c,但后缀还是mm或m。

总结:只要cpp文件和cpp include的文件中不包含obj-c的东西就可以用了,cpp混用obj-c的关键是使用接口,而不能直接使用实现代码,实际上cpp混用的是obj-c编译后的o文件,这个东西其实是无差别的,所以可以用。obj-c的编译器支持cpp.

 

54.目标-动作机制

答:目标是动作消息的接收者。一个控件,或者更为常见的是它的单元,以插座变量(参见"插座变量"部分) 的形式保有其动作消息的目标。

    动作是控件发送给目标的消息,或者从目标的角度看,它是目标为了响应动作而实现的方法。程序需要某些机制来进行事件和指令的翻译。这个机制就是目标-动作机制。

 

55. cocoa touch框架

这些框架包括:

Core Animation

通过Core Animation,您就可以通过一个基于组合独立图层的简单的编程模型来创建丰富的用户体验。

Core Audio

Core Audio是播放,处理和录制音频的专业技术,能够轻松为您的应用程序添加强大的音频功能。

Core Data提供了一个面向对象的数据管理解决方案,它易于使用和理解,甚至可处理任何应用或大或小的数据模型。

   功能列表:框架分类

   下面是 Cocoa Touch 中一小部分可用的框架:

     音频和视频

       CoreAudio

       OpenAL

       MediaLibrary

       AVFoundation

     数据管理

       Core Data

       SQLite

     图形和动画

       CoreAnimation

       OpenGL ES

       Quartz 2D

      网络/li>

        Bonjour

        WebKit

        BSDSockets

      用户应用

        AddressBook

        CoreLocation

        MapKit

        StoreKit

 

56.objc的内存管理

答:如果您通过分配和初始化(比如[[MyClass alloc] init])的方式来创建对象,您就拥有这个对象,需要负责该对象的释放。这个规则在使用NSObject的便利方法new 时也同样适用。

如果您拷贝一个对象,您也拥有拷贝得到的对象,需要负责该对象的释放。如果您保持一个对象,您就部分拥有这个对象,需要在不再使用时释放该对象。反过来,如果您从其它对象那里接收到一个对象,则您不拥有该对象,也不应该释放它(这个规则有少数的例外,在参考文档中有显式的说明)。

 

57.自动释放池是什么,如何工作?

答:当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。

1)ojc-c是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.

2) NSAutoreleasePool就是用来做引用计数的管理工作的,这个东西一般不用你管的.

3)autorelease和release没什么区别,只是引用计数减一的时机不同而已,autorelease会在对象的使用真正结束的时候才做引用计数减一。

 

58.类工厂方法是什么?

答:类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中,返回被创建的对象,并进行自动释放处理。这些方法的形式是+ (type)className...(其中 className不包括任何前缀)。工厂方法可能不仅仅为了方便使用。它们不但可以将分配和初始化合在一起,还可以为初始化过程提供对象的分配信息。类工厂方法的另一个目的是使类(比如NSWorkspace)提供单件实例。虽然init...方法可以确认一 个类在每次程序运行过程只存在一个实例,但它需要首先分配一个“生的”实例,然后还必须释放该实例。工厂方法则可以避免为可能没有用的对象盲目分配内存。

 

59. 单件实例是什么?

Foundation和Application Kit 框架中的一些类只允许创建单件对象,即这些类在当前进程中的唯一实例。举例来说,NSFileManager和NSWorkspace 类在使用时都是基于进程进行单件对象的实例化。当向这些类请求实例的时候,它们会向您传递单一实例的一个引用,如果该实例还不存在,则首先进行实例的分配和初始化。单件对象充当控制中心的角色,负责指引或协调类的各种服务。如果类在概念上只有一个实例(比如NSWorkspace),就应该产生一个单件实例,而不是多个实例;如果将来某一天可能有多个实例,您可以使用单件实例机制,而不是工厂方法或函数。

 

60.动态绑定

—在运行时确定要调用的方法

动态绑定将调用方法的确定也推迟到运行时。在编译时,方法的调用并不和代码绑定在一起,只有在消实发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术,您的代码每次执行都可以得到不同的结果。运行时因子负责确定消息的接收者和被调用的方法。运行时的消息分发机制为动态绑定提供支持。当您向一个动态类型确定了的对象发送消息时,运行环境系统会通过接收者的isa指针定位对象的类,并以此为起点确定被调用的方法,方法和消息是动态绑定的。而且,您不必在Objective-C 代码中做任何工作,就可以自动获取动态绑定的好处。您在每次发送消息时,特别是当消息的接收者是动态类型已经确定的对象时,动态绑定就会例行而透明地发生。

 

61.obj-c的优缺点objc

优点:  

1) Cateogies   2) Posing   3) 动态识别   4) 指标计算   5)弹性讯息传递   6) 不是一个过度复杂的 C 衍生语言   7) Objective-C 与 C++ 可混合编程

缺点:  

1) 不支援命名空间   2)  不支持运算符重载  3) 不支持多重继承  4) 使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。(如内联函数等),性能低劣。

 

62.sprintf,strcpy,memcpy使用上有什么要注意的地方?

答:strcpy是一个字符串拷贝的函数,它的函数原型为strcpy(char *dst, const char *src);将src开始的一段字符串拷贝到dst开始的内存中去,结束的标志符号为'\0',由于拷贝的长度不是由我们自己控制的,所以这个字符串拷贝很容易出错。

具备字符串拷贝功能的函数有memcpy,这是一个内存拷贝函数,它的函数原型为memcpy(char *dst,const char* src, unsigned int len);将长度为len的一段内存,从src拷贝到dst中去,这个函数的长度可控。但是会有内存叠加的问题。

sprintf是格式化函数。将一段数据通过特定的格式,格式化到一个字符串缓冲区中去。sprintf格式化的函数的长度不可控,有可能格式化后的字符串会超出缓冲区的大小,造成溢出。

 

转载于:https://www.cnblogs.com/ljwiOS/p/4821520.html

2017-08-25 02:17:46 Zurielhgq 阅读数 253
  • iOS开发-全面解析iOS蓝牙BLE4.0开发

    只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发

    3672 人正在学习 去看看 许英俊
2016-05-17 10:57:34 lcg910978041 阅读数 356
  • iOS开发-全面解析iOS蓝牙BLE4.0开发

    只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发

    3672 人正在学习 去看看 许英俊

1.NSThread基本运用

app启动时默认都是,包括ViewController里执行的都是在主线程执行的
当计算了过大的时候会造成线程阻塞,比如点击按钮执行下面的方法,只有计算完,结束后,程序才能继续执行,如果是死循环的话,会一直占用主线程,导致主线程无法继续进行

-(void)pressBtn:(UIButton*)btn
{
    int i=0;
    while (true)
    {
        i++;
        NSLog(@"i=%d",i);
        if (i==10000)
        {
        //主线程,只有执行了10000次循环才会退出这个方法,继续向下执行
            break;
        }
    }

}

这样就需要开启另外一个线程,开启的方式有两种
第一种:alloc init 需要手动的start 和cancel

-(void)pressBtnMuti:(UIButton*)btnMuti
{
    //创建一个多线程对象

    NSThread*thread=[[NSThread alloc]initWithTarget:self selector:@selector(thread01) object:nil];
    //启动线程
    [thread start];
}

-(void)thread01
{
    int i=0;
    while (true)
    {
        i++;
        NSLog(@"in thread i=%d",i);
        [NSThread sleepForTimeInterval:1];
        if (i>=10000)
        {
            //直接结束当前的线程
            //+方法
            //会判断是哪一个线程来执行的这个函数
            //线程是由操作系统来管理
            //向操作系统发送通知,要求结束当前的进程
            [NSThread exit];


            //获取当前线程对象
            NSThread*curThread=[NSThread currentThread];
            //通知操作从系统来取消当前线程的执行
            [curThread cancel];
        }
    }
}

第二种创建方式,直接开启并执行的一个线程,执行完方法程自动关闭

-(void)pressBtn{
[NSThread detachNewThreadSelector:@selector(thread02) toTarget:self withObject:nil];
}
-(void)thread02{
    NSLog(@"线程二执行");
    }

2.线程执行顺序
当一个方法同上开启另个线程,是执行顺序是不确定的,又系统资源决定的

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //开始执行线程1
    [NSThread detachNewThreadSelector:@selector(threadCount01) toTarget:self withObject:nil];
    //线程二:
     [NSThread detachNewThreadSelector:@selector(threadCount02) toTarget:self withObject:nil];
}

以下执行方法
conut1 final=200?
conut1 final=200?
不确定的,因为都是异步线程执行的方法,谁先执行完不确定,所以conut1 ,count2只有一个等于200,另一个不确定
而且每次run 结果极有可能不一样,考虑线程安全,需要上锁

-(void)threadCount01
{
    for (int i=0; i<100; i++)
    {
        //[_lock lock];
        _count++;
        //[_lock unlock];
        NSLog(@"Count=%d",_count);
    }

    NSLog(@"conut1 final=%d",_count);
}

-(void)threadCount02
{
    for (int i=0; i<100; i++)
    {
        [_lock lock];
        _count++;
        [_lock unlock];
        NSLog(@"Count=%d",_count);
    }

    NSLog(@"conut2 final=%d",_count);
}

同样的例子更加可以说明,线程是有操作系统资源决定

-(void)pressBtnMuti:(UIButton*)btn
{
    NSThread*threadAdd=[[NSThread alloc]initWithTarget:self selector:@selector(threadAdd) object:nil];
    [threadAdd start];

    [NSThread detachNewThreadSelector:@selector(threadMinus) toTarget:self withObject:nil];

}

-(void)threadAdd
{

    while (true)
    {
        [_lock lock];
        _value++;
        [_lock unlock];
         NSLog(@"value++=%d",_value);
      [NSThread sleepForTimeInterval:arc4random()%5];
         //[NSThread sleepForTimeInterval:1];
    }
}
-(void)threadMinus
{
    while (true)
    {
        [_lock lock];
        _value--;
        [_lock unlock];
        NSLog(@"value--=%d",_value);

        [NSThread sleepForTimeInterval:arc4random()%5];
         //[NSThread sleepForTimeInterval:1];
    }

}

执行结果等一段时间 value的值是不确定的
这里写图片描述

3.关于线程锁,多个线程对同一个数组进行访问,读写操作都要考虑加锁

//不考虑线程安全
-(void)addElment:(NSObject*)elem
{
    if (elem==nil)
        return ;
//        if ([_arrayQueue count]==0)
//        {
//            _arrayQueue=[[NSMutableArray alloc]init];
//        }
    if ([_arrayQueue count]>KMaxArrayQueue) {
        return ;
    }

    [_arrayQueue addObject:elem];

}
//不考虑线程安全
-(id)getElement
{

    if ([_arrayQueue count]==0)
    return nil;

    id obj=[_arrayQueue objectAtIndex:0];
    [_arrayQueue removeObjectAtIndex:_arrayQueue.count-1];
    return obj;
}


-(void)addElmentThreadSafty:(id)obj
{
    [_lock lock];
    [self addElment:obj];
    [_lock unlock];
}

-(id)getElementThreadSafty
{
    [_lock lock];
    id obj= [self getElement];
    [_lock unlock];
    return obj;
}

4.线程可以手动的取消

- (void)run
{
    for(int i = 0 ; i < 100 ; i++)
    {
        if([NSThread currentThread].isCancelled)
        {
            // 终止当前正在执行的线程
            [NSThread exit];
        }
        NSLog(@"-----%@----%d" , [NSThread currentThread].name, i);
        // 每执行一次,线程暂停0.5秒
        [NSThread sleepForTimeInterval:0.5];
    }
}
- (IBAction)cancelThread:(id)sender
{
    // 取消thread线程,调用该方法后,thread的isCancelled方法将会返回NO
    [thread cancel]; // ①
}

5.线程的优先级, 改变线程的优先级,可以改变输出顺序
优先级相同,输出不确定,当不一样的时候优先级高的for循环先执行完,然后执行另外优先级低的for循环

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"UI线程的优先级为:%g" , [NSThread threadPriority]);//0.5
    // 创建第一个线程对象
    NSThread* thread1 = [[NSThread alloc]
        initWithTarget:self selector:@selector(run) object:nil];
    // 设置第一个线程对象的名字
    thread1.name = @"线程A";
    NSLog(@"线程A的优先级为:%g" , thread1.threadPriority);
    // 设置使用最低优先级
    thread1.threadPriority = 1.0;
    // 创建第二个线程对象
    NSThread* thread2 = [[NSThread alloc]
        initWithTarget:self selector:@selector(run) object:nil];
    // 设置第二个线程对象的名字
    thread2.name = @"线程B";
    NSLog(@"线程B的优先级为:%g" , thread2.threadPriority);
    // 设置使用最高优先级
    thread2.threadPriority = 0;
    // 启动2个线程
    //改变线程的优先级,可以改变输出顺序
    [thread1 start];
    [thread2 start];
}
- (void)run
{
    for(int i = 0 ; i < 100 ; i++)
    {
        NSLog(@"-----%@----%d" , [NSThread currentThread].name, i);
    }
}

6.应用举例1
在一个循环(for i in 20)里开启另外一个线程,另外一个线程执行一个(for i in 5),请问打印结果?

- (void)viewDidLoad
{
[super viewDidLoad];
    NSLog(@"===%@" , [NSThread currentThread]);//其实就是主线程
   // ===<NSThread: 0x7fea61d130b0>{number = 1, name = main}
for(int i = 0 ; i < 20 ; i++) {
        NSLog(@"===%d"  , i);
        if(i == 5) {
            // 创建线程对象
            NSThread *thread = [[NSThread alloc]initWithTarget:self
                selector:@selector(run) object:nil];
            // 启动新线程
            NSLog(@"thread==%@",thread);
            //thread==<NSThread: 0x7facaa478610>{number = 2, name = main}
            [thread start];
//          // 创建并启动新线程
//          [NSThread detachNewThreadSelector:@selector(run) toTarget:self
//              withObject:nil];
        }
    }
}
- (void)run
{
    for(int i = 0 ; i < 5 ; i++) {
        NSLog(@"-----%@----%d" , [NSThread currentThread].name, i);
    }
}

打印结果:
这里写图片描述
如果再次run一下,打印结果为:
这里写图片描述
为何不一样呢,因为开启的线程,不是在主线程,而且是异步执行,什么时候开始执行,取决于系统资源,所以会不一致

7.应用举例2
利用NSThread如何实现适时更改UIProgressView的进度条呢?,
方法:开启一个异步线程,执行方法改变progress,执行主线程方法,改变UI,属于异步执行,同步UI

//使用主线程来调用函数
-(void)pressMian{
    //参数二:函数中的参数
    //参数三:是否等待主线程空余时执行
    //如果为NO 不需要等待
    [self performSelectorOnMainThread:@selector(updateProgressMain:) withObject:_progressView waitUntilDone:NO];
}

//主线程主使用
//方法一:
-(void)updateProgressMain:(UIProgressView*)pView
{
    while (_progressView.progress<1)
    {
        _progressView.progress+=0.001;
        NSLog(@"_progress=%f",_progressView.progress);

    }

}

#pragma mark 开启一个异步线程,执行方法改变progress,执行主线程方法,改变UI,属于异步执行,同步UI
//方法二:
-(void)pressMian2
{
    [NSThread detachNewThreadSelector:@selector(updateProgress02) toTarget:self withObject:nil];

}

-(void)updateProgress02
{
    while (_curProgress<=1){
        _curProgress+=0.0001;
        //获得主线程
        NSThread*mainT=[NSThread mainThread];

        //执行一个函数,指定某个线程来执行某个函数
        [self performSelectorOnMainThread:@selector(changeProgress) withObject:mainT waitUntilDone:YES];
    }
}

//主线程中执行函数
-(void)changeProgress
{
    _progressView.progress=_curProgress;
        NSLog(@"_progress=%f",_progressView.progress);
    if (_progressView.progress==1)
    {
        _progressView.progress=0;
        return;
    }
}

#pragma mark 开启普通线程,进度条会在progress=1是突然出现
//开启普通线程
-(void)pressThread{
    NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(updateProgress) object:nil];
    [thread start];
}
//普通线程函数
-(void)updateProgress {
    while  (_progressView.progress<1.0f){
        _progressView.progress+=0.0001;
            NSLog(@"_progress=%f",_progressView.progress);
        if (_progressView.progress==1){
            return;
        }
    }
}

8应用举例3
异步下载一张图片,同步更新Image

- (IBAction)showImage:(id)sender
{
    NSString* url = @"http://www.crazyit.org/logo.jpg";
    // 创建新线程对象
    NSThread *thread = [[NSThread alloc]initWithTarget:self
        selector:@selector(downloadImageFromURL:) object:url];
    // 启动线程
    [thread start];
}
// 定义一个方法作为线程执行体。
-(void)downloadImageFromURL:(NSString *) url
{
    // 从网络获取数据
    NSData *data = [[NSData alloc]
        initWithContentsOfURL:[NSURL URLWithString:url]];
    // 将网络数据初始化为UIImage对象
    UIImage *image = [[UIImage alloc]initWithData:data];
    if(image != nil)
    {
        // 在主线程中执行updateUI:方法
        [self performSelectorOnMainThread:@selector(updateUI:)
            withObject:image waitUntilDone:YES]; // ①
    }
    else
    {
        NSLog(@"---下载图片出现错误---");
    }
}
-(void)updateUI:(UIImage*) image
{
    self.iv.image = image;
}

关于线程和进程的基本概念一篇比较好的博客参考:
http://www.cnblogs.com/wendingding/p/3805088.html

没有更多推荐了,返回首页