IOS interview questions object-c 11-20

11. Explain the self = [super init] method?

Fault tolerance processing, when the parent class fails to initialize, a nil will be returned, indicating that the initialization failed.

Due to inheritance, subclasses need to have instances and behaviors of the parent class. Therefore, we must initialize the parent class first and then initialize the subclass.

12. Briefly describe the advantages of using block?
The code is compact, value passing and callbacks are very convenient , and a lot of code for writing agents is saved.

The block encapsulated by NSTimer, the specific implementation method:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
        repeats:YES
        callback :^() {                 weakSelf.secondsLabel.text = ...         } [[NSRunLoop currentRunLoop] addTimer: timer forMode:NSRunLoopCommonModes];


13. Is there a two-dimensional array in Objective-C? How to implement a two-dimensional array?

In actual project development, two-dimensional arrays are also commonly used data structures .

Two-dimensional arrays in OC are also created through one-dimensional arrays. Today we will explain in detail how to use two-dimensional arrays in OC. One-dimensional arrays and two-dimensional arrays initialized
with NSArray are immutable arrays .

#import
int main(int argc, const char * argv[]) { @autoreleasepool {         //Define 2 one-dimensional arrays; NSArray *firstRow = [[NSArray alloc] initWithObjects:@"1",@"2",@ "3", nil]; NSArray *secondRow = [[NSArray alloc] initWithObjects:@"4",@"5",@"6", nil];         //Use a one-dimensional array to initialize a two-dimensional array; NSArray * my2DArray = [[NSArray alloc] initWithObjects:firstRow,secondRow, nil];         //Output a two-dimensional array object;         NSLog(@"two-dimensional array: %@",my2DArray);         //Traverse the two-dimensional array;         for (int i = 0; i < [ my2DArray count]; i++) {                         for (int j = 0; j < firstRow.count; j++) {                                 NSLog(@"Two-dimensional array element: %@",[[my2DArray objectAtIndex :i] objectAtIndex :j]);                         }                 }         }         return 0; }
        


        
        


        











14. Briefly describe the function of the modifier of the property attribute?
getter =getName, setter =setName: set the method names of setter and getter;
readwrite , readonly : set the access level;
assign : The method directly assigns the value without any retain operation, in order to solve the problem of original type and circular reference;
retain : Its setter method releases the old value of the parameter and then retains the new value. All implementations follow this order;

copy : Its setter method performs a copy operation, which is the same as the retain processing process. The old value is first released, and then the new object is copied. The retainCount is 1.

This is a mechanism introduced to reduce dependence on context.

nonatomic : non-atomic access, no synchronization, multi-threaded concurrent access will improve performance.

Note that if this attribute is not added, the default is that both access methods are atomic transaction access.

15. Convert the formatted date string "2015-04-10" to NSDate type

NSString *timeStr = @"2015-04-10";


NSDateFormatter *formatter = [[NSDateFormatter alloc] init];


formatter.dateFormat = @"yyyy-MM-dd";


formatter.timeZone = [NSTimeZone defaultTimeZone];


NSDate *date = [formatter dateFromString:timeStr];


// 2015-04-09 16:00:00 +0000
NSLog(@"%@", date);

16、简述SDWebImage内部实现过程?
入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。
进入 SDWebImageManager-downloadWithURL: delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:.
先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。
如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存

根据 URLKey 在硬盘缓存目录下尝试读取图片文件。

这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。

如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo: 。
共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。

图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理
图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。

将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存

写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。

SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。

SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。

SDWebImagePrefetcher 可以预先下载图片,方便后续使用

17、 为什么 Objective-C 的方法调用要用方括号?

首先要说的是,Objective-C 的历史相当久远,如果你查 wiki 的话,你会发现:Objective-C 和 C++ 这两种语言的发行年份都是 1983 年。在设计之初,二者都是作为 C 语言的面向对象的接班人,希望成为事实上的标准。

最后结果大家都知道了,C++ 最终胜利了,而 Objective-C 在之后的几十年中,基本上变成了苹果自己家玩的玩具。不过最终,由于 iPhone 的出现,Objective-C 迎来了第二春,在 TOBIE 语言排行榜上,从 20 名开外一路上升,排名曾经超越过 C++,达到了第三名,但是随着 swift 的出现,Objective-C 的排名则一路下滑

Objective-C 在设计之初参考了不少 Smalltalk 的设计,而消息发送则是向 Smalltalk 学来的。Objective-C 当时采用了方括号的形式来表示发送消息,为什么没有选择用点呢?

我个人觉得是,当时市面上并没有别的面向对象语言的设计参考,而 Objective-C 「发明」了方括号的形式来给对象发消息,而 C++ 则「发明」了用点的方式来 “发消息”。

有人可能会争论说 C++ 的「点」并不是真正的发消息,但是其实二者都是表示「调用对象所属的成员函数」。

另外,有读者评论说使用方括号的形式是为了向下兼容 C 语言,我并不觉得中括号是唯一选择,C++ 不也兼容了 C 语言么?Swift 不也可以调用 C 函数么?
最终,其实是 C++ 的「发明」显得更舒服一些,所以后来的各种语言都借鉴了 C++ 的这种设计,也包括 Objective-C 在内。Objective-C 2.0 版本中,引入了 dot syntax,即:
a = obj.foo 等价于 a = [obj foo]
obj.foo = 1 则等价于 [obj setFoo:1]
Objective-C 其实在设计之中确实是比较特立独行的,除了方括号的函数调用方式外,还包括比较长的,可读性很强的函数命名风格。
我个人并不讨厌 Objective-C 的这种设计,但是从 Swift 语言的设计来看,苹果也开始放弃一些 Objective-C 的特点了,比如就去掉了方括号这种函数调用方式。
所以,回到我们的问题,我个人认为,答案就是:Objective-C 在 1983 年设计的时候,并没有什么有效的效仿对象,于是就发明了一种有特点的函数调用方式,现在看起来,这种方式比点操作符还是略逊一筹。

大多数语言一旦被设计好,就很难被再次修改,应该说 Objective-C 发明在 30 年前,还是非常优秀的,它的面向对象化设计得非常纯粹,比 C++ 要全面得多,也比 C++ 要简单得多。
 18、如何创建一个可以被取消执行的 block?
// 方法一:创建一个类,将要执行的 block 封装起来,然后类的内部有一个 _isCanceled 变量,在执行的时候,检查这个变量,如果 _isCanceled 被设置成 YES 了,则退出执行。
        typedef void (^Block)();
        @interface CancelableObject : NSObject
                - (id)initWithBlock:(Block)block;
                - (void)start;
                - (void)cancel;
        @end
@implementation CancelableObject {
        BOOL _isCanceled;
        Block _block;
}
- (id) initWithBlock: (Block)block {
        self = [super init];
        if (self != nil) {
                _isCanceled = NO;
                _block = block;
        }
        return self;
}
- (void) start {
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_global_queue(0, 0),
        ^{

                if (weakSelf) {
                        typeof(self) strongSelf = weakSelf;
                        if (!strongSelf->_isCanceled) {
                                (strongSelf->_block)();
                        }
                }
        });
}

- (void) cancel {
        _isCanceled = YES;
}

@end

// 另外一种写法,将要执行的 block 直接放到执行队列中,但是让其在执行前检查另一个 isCanceled 的变量,然后把这个变量的修改实现在另一个 block 方法中,如下所示:


typedef void (^CancelableBlock)();
typedef void (^Block)();

+ (CancelableBlock) dispatch_async_with_cancelable:(Block)block {
        __block BOOL isCanceled = NO;
        CancelableBlock cb = ^() {
                isCanceled = YES;
        };

        dispatch_async(dispatch_get_global_queue(0, 0), ^{
                if (!isCanceled) {
                        block();
                }
        });

        return cb;
}

以上两种方法都只能在 block 执行前有效,如果要在 block 执行中有效,只能让 block 在执行中,有一个机制来定期检查外部的变量是否有变化,而要做到这一点,需要改 block 执行中的代码。

在本例中,如果 block 执行中的代码是通过参数传递进来的话,似乎并没有什么办法可以修改它了

19、简述IOS __block和__weak修饰符的区别?
1、__weak:
__weak只能在ARC下使用,且只能修饰对象,不能修饰基本数据类型(int等),弱引用,可以block解决循环引用问题。
2、__block:
__block既能再ARC下使用,也能在 MRC下使用。既能修饰对象又能修饰基本数据类型。
ARC、MRC区别:__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用。
ARC、MRC共同点:block内对于栈上的数据不能修改,使用__block修饰以后放到了堆上就可以修改了。
20、解释单例的写法在单例中使用数组要注意什么?
static PGSingleton *sharedSingleton;

+ (instancetype)sharedSingleton
{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
                sharedSingleton = [[PGSingleton alloc] init];
        });
        return sharedSingleton;
}
其实上面的还不是标准的单例方法,标准的单例方法需要重写 copyWithZone,allocWithZone,init,确保以任何方式创建出来的对象只有一个,这里就不详细写了。

单例使用 NSMutableArray 的时候,防止多个地方对它同时遍历和修改的话,需要加原子属性

并且property用strong,并且写一个遍历和修改的方法。

加上锁. Lock,UnLock.(PS:考虑性能问题尽量避免使用锁,在苹果的文档张看到的不要问我为什么,我也忘了自己查去。。)

Guess you like

Origin blog.csdn.net/u013491829/article/details/136570886