将来跳槽用

2018 iOS 面试题 待整理

2018-02-05  本文已影响49人  SunnyLeong

1、属性readwrite,readonly,assign,retain,copy,nonatomic 各自什么作用,他们在那种情况下用?

2、Objective-C如何对内存管理的,说说你的看法以及你遇到的问题以及解决方法?

​ Objective-C使用引用计数来管理内存,对象有个计数器,用以表示当前有多少个事物想令此对象继续存活下去。

3、内存管理的几条原则时什么?按照默认法则.哪些关键字生成的对象需要手动释放?在和property结合的时候如何有效的避免内存泄露?

4、MVC设计模式是什么? 你还熟悉什么设计模式?他们和MVC有什么不同的地方?

    @interface A:UIView
    id transparendValueDelegate;
    @property(nomatic, retain) id transparendValueDelegate;

    @end

    @implementation A
    @synthesize transparendValueDelegate

    -(void)Call
    { 
    NSString* value = @"你好";
    [transparendValueDelegate transparendValue: value];
    }

    @end
    @interface B:UIView

    NSString* value;
    @end

    @implementation B
    -(void)transparendValue:(NSString*)fromValue
    {
    value = fromValue;
    NSLog(@"%@ ,我是B",value); 
    }
    @end

使用时:

    A* a = [[A alloc] init];
    B* b = [[B alloc] init];
    a. transparendValueDelegate = b;//设置A代理委托对象为B
    [a Call];

这样就会输出:

**你好,我是B**

 委托模式关键就在于一个“**被”**字。这个B是很被动的,随时就会被你A Call一下。

5、浅复制和深复制的区别?

NSString *string = @”dddd";

NSString *stringCopy = [string copy];

NSMutableString *stringDCopy = [string mutableCopy];

[stringMCopy appendString:@``"!!"``];

查看内存可以发现,string和stringCopy指向的是同一块内存区域(weak reference),引用计数没有发生改变。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,是两个独立的字符串内容是一样的。

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

    MyObj *copy = [[[self class] allocWithZone :zone] init];

    copy->name = [_name copy];

    copy->imutableStr = [_imutableStr copy];

    copy->age = age;

    return copy;

}

mutableCopy构造

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

    MyObj *copy = NSCopyObject(self, 0, zone);

    copy->name = [_name mutableCopy];

    copy->age = age;

    return copy;

}

6、什么是KVO和KVC?他们的使用场景是什么?

image

7、通知和协议有哪些不同之处?

8、在iOS应用有哪些方式保存本地数据?他们都应用在哪些场景?

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    //保存值(key值同名的时候会覆盖的)  

    [defaults setObject:@"用户名" forKey:kUsernameKey];

    //立即保存

    [defaults synchronize];

    //取值

    NSString *username = [defaults objectForKey:kUsernameKey];

    //保存NSInteger
    [defaults setInteger:(NSInteger) forKey:(nonnull NSString *)];
    //保存BOOL
    [defaults setBool:(BOOL) forKey:(nonnull NSString *)];
    //保存NSURL
    [defaults setURL:(nullable NSURL *) forKey:(nonnull NSString *)];
    //保存float
    [defaults setFloat:(float) forKey:(nonnull NSString *)];
    //保存double
    [defaults setDouble:(double) forKey:(nonnull NSString *)];

    [defaults integerForKey:(nonnull NSString *)];
    [defaults boolForKey:(nonnull NSString *)];
    [defaults URLForKey:(nonnull NSString *)];
    [defaults floatForKey:(nonnull NSString *)];
    [defaults doubleForKey:(nonnull NSString *)];

    [defaults removeObjectForKey:(nonnull NSString *)];

   #import "Coding.h"
    #import <objc/runtime.h>
    @implementation Coding
     /**
     *  根据类动画获取类的所有属性,不要忘记导入#import <objc/runtime.h>
     *
     *  @param cls <#cls description#>
     *
     *  @return <#return value description#>
     */
    - (NSArray *)perperiesWithClass:(Class)cls
    {

        NSMutableArray *perperies = [NSMutableArray array];

        unsigned int outCount;
        //动态获取属性
        objc_property_t *properties = class_copyPropertyList(cls, &outCount);

        //遍历person类的所有属性
        for (int i = 0; i < outCount; i++)
        {
            objc_property_t property = properties[i];
            const char *name = property_getName(property);
            NSString *s = [[NSString alloc] initWithUTF8String:name];

            [perperies addObject:s];

        }

        return perperies;
    }

    /**
     *  归档会触发
     *
     *  @param aCoder <#aCoder description#>
     */
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        for (NSString *perperty in [self perperiesWithClass:[self class]])
        {
            [aCoder encodeObject:perperty forKey:perperty];
        }
    }

    /**
     *  解归档会触发
     *
     *  @param aDecoder <#aDecoder description#>
     *
     *  @return <#return value description#>
     */
    - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        if (self = [super init])
        {
            for (NSString *perperty in [self perperiesWithClass:[self class]])
            {
                [self setValue:[aDecoder decodeObjectForKey:perperty] forKey:perperty];;
            }

        }

        return self;
    }

    @end

    Coding *coding1 = [[Coding alloc] init];
     coding1.name = @"小明";
     coding1.age = 12;

     Coding *coding2 = [[Coding alloc] init];
     coding1.name = @"小王";
     coding1.age = 20;

     NSArray *array = @[coding1, coding2];

     //保存对象转化为二进制数据(一定是可变对象)
     NSMutableData *data = [NSMutableData data];

     //1.初始化
     NSKeyedArchiver *archivier = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
     //2.归档
     [archivier encodeObject:array forKey:@"key"];

     //3.完成归档
     [archivier finishEncoding];

     //4.保存
     [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"data"];

    //1.获取保存的数据
     NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"data"];

     //2.初始化解归档对象
     NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

     //3.解归档
     NSArray *persons = [unarchiver decodeObjectForKey:@"key"];

     //4.完成解归档
     [unarchiver finishDecoding];

    //把字典写入到plist文件,比如文件path为:~/Documents/data.plist
    [dictionary writeToFile:path atomically:YES];
    //把数组写入到plist文件中
    [array writeToFile:path atomically:YES];

    NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:(nonnull NSString *)]];
    NSDictionary *dictionary =  [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:(nullable NSString *) ofType:(nullable NSString *)]];

    NSArray *array = [NSArray arrayWithContentsOfURL:[NSURL fileURLWithPath:(nonnull NSString *)]];
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:(nullable NSString *) ofType:(nullable NSString *)]];

      //数据库对象
        sqlite3 *contactDB;

        const char *path = [[self databasePath] UTF8String];

       if (sqlite3_open(path, &contactDB) == SQLITE_OK)
       {
            char *errMsg;
            const char *sql_stmt = "CREATE TABLE IF NOT EXISTS CONTACTS(ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT,PHONE TEXT)";
           //执行语句
          if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
            {
                    //创建表失败
             }
       }
       else 
        {
                //打开数据库失败
        }
        sqlite3_close(contactDB);

      //是一个抽象类型,是一个句柄,在使用过程中一般以它的指针进行操作
      sqlite3_stmt *statement;

      //数据库路径 
      const char *path = [[self databasePath] UTF8String];

      //使用的时候打开数据库
      if (sqlite3_open(path, &contactDB) == SQLITE_OK)
      {
          NSString *insertSQL = [NSString stringWithFormat:@"INSERT INTO CONTACTS (name,address,phone) VALUES(\"%@\",\"%@\",\"%@\")",name.text,address.text,phone.text];

          const char *insert_stmt = [insertSQL UTF8String];
         // 这个函数将sql文本转换成一个准备语句(prepared statement)对象,同时返回这个对象的指针。这个接口需要一个数据库连接指针以及一个要准备的包含SQL语句的文本。它实际上并不执行这个SQL语句,它仅仅为执行准备这个sql语句
          sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
          //执行这个sql
          if (sqlite3_step(statement) == SQLITE_DONE)
          {
              //TODO:已存储到数据库;
          }
          else
          {
              //TODO:保存失败
          }
          //销毁statement对象
          sqlite3_finalize(statement);
          //关闭数据库
          sqlite3_close(contactDB);
      }

      //数据库路径
      const char *path = [[self databasePath] UTF8String];
      //查询结果集对象句柄
      sqlite3_stmt *statement;

      //打开数据库
      if (sqlite3_open(path, &contactDB) == SQLITE_OK)
      {
          //查询的sql语句
          NSString *querySQL = [NSString stringWithFormat:@"SELECT address,phone from contacts where name=\"%@\"",name.text];
          const char *query_stmt = [querySQL UTF8String];

          //执行查询sql语句
          if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK) 
          {
              //遍历每条数据
              if (sqlite3_step(statement) == SQLITE_ROW) 
              {
                  //获取每条数据的字段。
                  NSString *addressField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
                  address.text = addressField;

                  NSString *phoneField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 1    )];
                  phone.text = phoneField;

                  //TODO:已查到结果
              }
              else
              {
                  //TODO:未查到结果
              }
              sqlite3_finalize(statement);
          }

          sqlite3_close(contactDB);
      }

    - (NSManagedObjectContext *)context
    {
     AppDelegate *app = [UIApplication sharedApplication].delegate;

     return app.managedObjectContext;
    }

    //创建Person对象
    /*
    insertNewObjectForEntityForName:就是创建的实体名字。
    inManagedObjectContext:上下文,appDelegate里面已经创建完成。
    */
     Person *person = [NSEntityDescription
                       insertNewObjectForEntityForName:@"Person"
                       inManagedObjectContext:[self context]];

     //赋值
     [person setValue:@"小王" forKey:@"name"];
     [person setValue:@(35) forKey:@"age"];

     //保存
     if (![[self context] save:nil])
     {
        //TODO:保存失败
     }

    //创建查询对象
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];

    #if 0
        //条件查询
        //NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<=35"];
        //查询名字带有王的
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like[cd]'*王*'"];
    //设置查询条件
        request.predicate = predicate;
    #endif

        //排序
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
     //设置排序条件
        request.sortDescriptors = @[sort];

        //执行查询
        NSArray *objectArray = [[self context] executeFetchRequest:request error:nil];

       //遍历查询结果
        for (Person *p in objectArray)
        {
            NSLog(@"%@ - %@",[p valueForKey:@"name"],[p valueForKey:@"age"]);
        }

    //先查询要修改的对象
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];

        //设置查询条件
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name='小王' and age = 35"];
        request.predicate = predicate;

        //执行查询
        NSArray *objectArray = [[self context] executeFetchRequest:request error:nil];

        //遍历要修改的对象
        for (Person *p in objectArray)
        {
            //修改(修改内存数据,没有同步数据库)
            [p setValue:@(45) forKey:@"age"];
        }
        //同步数据库
        [[self context] save:nil];

    //查询要删除的数据
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];

        //设置查询条件
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name='小王'"];
        request.predicate = predicate;

        //执行查询
        NSArray *objectArray = [[self context] executeFetchRequest:request error:nil];

        //遍历删除
        for (Person *p in objectArray)
        {
            //删除内存中的数据
            [[self context] deleteObject:p];
         }

        //同步数据库
        [[self context] save:nil];

      // 初始化一个保存用户帐号的KeychainItemWrapper 
      KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Your Apple ID" accessGroup:@"YOUR_APP_ID.com.yourcompany.AppIdentifier"];
      //保存帐号
      [wrapper setObject:@"<帐号>" forKey:(id)kSecAttrAccount];  
      //保存密码
      [wrapper setObject:@"<帐号密码>" forKey:(id)kSecValueData];

      //从keychain里取出帐号密码
      NSString *password = [wrapper objectForKey:(id)kSecValueData];

      //清空设置
      [wrapper resetKeychainItem];

      //获取密码密码
      +(NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;
      //存储密码
      +(BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error;
      //删除密码
      +(BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

      //创建一个uuid
      NSString *uuidString = [self uuidString];
      //31C75924-1D2E-4AF0-9C67-96D6929B1BD3

      [SFHFKeychainUtils storeUsername:kKeyChainKey andPassword:uuidString forServiceName:kKeyChainGroupKey updateExisting:NO error:nil];

      -(NSString *)uuidString
      {
        //创建一个uuid
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        CFStringRef stringRef = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);

        NSString *uuidString = (__bridge NSString *)(stringRef);

        CFRelease(uuidRef);

        return uuidString;
      }
上一篇下一篇

猜你喜欢

热点阅读