struct file_operations是一个字符设备把驱动的 *** 作和设备号联系在一起的纽带,是一系列指针的集合肆核,每个被打开的文件都对应于一系列的 *** 作,这就是file_operations,用来执行一系列的系统调用。
struct file代表一个打开的文件,在执行file_operation中的open *** 作时被创建,这里需要注意的是与用户空间inode指针的区别,一个在内核,而file指针在用户空间,由c库来定义。
struct inode被内核用来代表一个文件,注意和struct file的区别,struct inode一个是代表文薯雹棚件,struct file一个是代表打开的文件。
楼主如果对数则Linux系统感兴趣,想学习更多Linux系统知识,可以百度《Linux就该这么学》,不错的一本Linux系统入门教程。
每个苹果技术开发者可能都遇见过令人沮丧的情况,那就是当你点击某个ios应用或者mac应用时,或者当你点击按钮或者输入文本时,突然间,用户交互界面停止了响应。在一款移动端iOS程序中,用户期望你的app可以即时地响应他们的触摸 *** 作,然而app反应迟钝或者不反应就会让人非常厌烦,用户通常会给出不好的评价。
然而说的容易做就难。一旦你的app需要执行多个任务,事情很快就会变得复杂起来。在主运行回路中并没有很多时间去执行繁重的工作,并且还有一直提供可响应的UI界面。
两难的开发者要怎么做呢?一种方法是通过并发 *** 作将部分任务从主线程中撤离。并发 *** 作意味着你的程序可以在 *** 作中同时执行多个流(或者线程)-这样,当你执行任务时,交互界面可以保持响应。
一种在iOS中执行并发 *** 作的方法,是使用NSOperation和NSOperationQueue类。在本教程中,你将学习如何使用它们!你会先创建一款不使用多线程的app,这样它会变得响应非常迟钝。然后改进程序,添加上并行 *** 作–并且希望–可以提供一个交互响应更好的界面给用户!
在开始阅读这篇教程之前,先阅读我们的 Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial会很有帮助。然而,因为本篇教程比较通俗易懂,所以也可以不必阅读这篇文章。
背景知识
在你学习这篇教程之前,有几个技术概念需要先解决下。
也许你听说过并发和并行 *** 作。从技术角顷逗度来看,并发是程序的属性,而并行运作是机器的属性。并行和并发是两种分开的概念。作为程序员,你不能保证你的代码会在能并行执行你的代码的机器上运行。然而,你可以设计你的代码,让它使用并发 *** 作。
首先,有必要定义几个术语:
任务:一项需要完成的,简单,单一的任务。
线程:一种由 *** 作系统提供的机制,允许多条指令在一个单独的程序中同时执行。
进程:一段可执行的代码,它可以由几个线程组成。
(注意:在iPhone和Mac中,线程功能是由POSIXThreadsAPI(或者pthreads)提供的,它是 *** 作系统的一部分。这是相当底层的东西,你会发现很容易犯错;也许线程最坏的地方就是那些极难被发现的错误吧!
Foundation框架包含了一个叫做NSThread的类,他更容易处理,但是使用NSThread管理多个线程仍然是件令人头疼的事情。NSOperation和NSOperationQueue是更高级别的类,他们大大简化了处理多个线程的过程。)
在这张图中,你可以看到进程,线程和任务之间的关系:
在这张图中,线程2执行了读文件的 *** 作,而线程1执行了用户界面相关的代码。这跟你在iOS中构建你的代码很相似–主线程应该执行任何与用户界面有关的任务,然后二级线程应该执行缓慢的或者长时间的 *** 作(例如读文雀侍卖件,访问网络等等)
NSOperationvs.GrandCentralDispatch(GCD)
你也许听说过GrandCentralDispatch(GCD)。简而言之,GCD包含语言特谈简性,运行时刻库和系统增强(提供系统性和综合性的提升,从而在iOS和OSX的多核硬件上支持并发 *** 作)。如果你希望更多的了解GCD,你可以阅读Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial教程。
在MacOSXv10.6和iOS4之前,NSOperation与NSOperationQueue不同于GCD,他们使用了完全不同的机制。从MacOSXv10.6和iOS4开始,NSOperation和NSOperationQueue是建立在GCD上的。作为一种通例,苹果推荐使用最高级别的抽象,然而当评估显示有需要时,会突然降到更低级别。
以下是对两者的快速比较,它会帮助你决定何时何地去使用GCD或者NSOperation和NSOperationQueue
GCD是一种轻量级的方法来代表将要被并发执行的任务单位。你并不需要去计划这些任务单位;系统会为你做计划。在块(block)中添加依赖会是一件令人头疼的事情。取消或者暂停一个块会给一个开发者产生额外的工作!
NSOperation和NSOperationQueue对比GCD会带来一点额外的系统开销,但是你可以在多个 *** 作(operation)中添加附属。你可以重用 *** 作,取消或者暂停他们。NSOperation和 Key-Value Observation (KVO)是兼容的;例如,你可以通过监听NSNotificationCenter去让一个 *** 作开始执行。
初步的工程模型
在工程的初步模型中,你有一个由字典作为其数据来源的table view。字典的关键字是图片的名字,每个关键字的值是图片所在的URL地址。本工程的目标是读取字典的内容,下载图片,应用图片滤镜 *** 作,最后在table view中显示图片。
以下是该模型的示意图:
(注意:如果你不想先创建一个非线程版本的工程,而是想直接进入多线程方向,你可以跳过这一节,下载我们在本节中创建的第一版本工程。所有的图片来自stock.xchng。在数据源中的某些图片是有意命名错误,这样就有例子去测试下载图片失败的情况。)
启动Xcode并使用iOSApplicationEmpty Application模版创建一个新工程,然后点击下一步。将它命名为ClassicPhotos。选择Universal, 勾选上Use Automatic Reference Counting(其他都不要选),然后点击下一步。将工程保存到任意位置。
从Project Navigator中选择ClassicPhoto工程。选择Targets ClassicPhotosBuild Phases 然后展开Link Binary with Libraries。使用+按钮添加Core Image framework(你将需要Core Image来做图像滤镜处理)。
在Project Navigator中切换到AppDelegate.h 文件,然后导入ListViewController文件 — 它将会作为root view controller,接下来你会定义它。ListViewController是UITableViewController的子类。
#import "ListViewController.h"
切换到AppDelegate.m,定位到application:didFinishLaunchingWithOptions:,实例化一个ListViewController的对象,然后设置他为UIWindow的root view controller。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]
self.window.backgroundColor = [UIColor whiteColor]
/*
ListViewController is a subclass of UITableViewController.
We will display images in ListViewController.
Here, we wrap our ListViewController in a UINavigationController, and set it as the root view controller.
*/
ListViewController *listViewController = [[ListViewController alloc] initWithStyle:UITableViewStylePlain]
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:listViewController]
self.window.rootViewController = navController
[self.window makeKeyAndVisible]
return YES
}
注意:加入在这之前你还没有创建界面,这里给你展示不使用Storyboards或者xib文件,而是程序来创建界面。在这篇教程里面,我们就简单使用一下这样的方式。
下面就创建一个UITableViewController的子类,命名为ListViewController。切换到ListViewController.h,做一下修改:
// 1
#import
#import
// 2
#define kDatasourceURLString @"http://www.raywenderlich.com/downloads/ClassicPhotosDictionary.plist"
// 3
@interface ListViewController : UITableViewController
// 4
@property (nonatomic, strong) NSDictionary *photos// main data source of controller
@end
现在让我们来看看上面代码的意思吧:
1、引入UIKitandCoreImage,也就是import头文件。
2、为了方便点,我们就宏定义kDatasourceURLString这个是数据源的地址字符串。
3、然后让ListViewController成为UITableViewController的子类,也就是替换NSObject为UITableViewController。
4、声明一个NSDictionary的实例对象,这个也就是数据源。
现在切换到ListViewController.m,也做下面的改变:
@implementation ListViewController
// 1
@synthesize photos = _photos
#pragma mark -
#pragma mark - Lazy instantiation
// 2
- (NSDictionary *)photos {
if (!_photos) {
NSURL *dataSourceURL = [NSURL URLWithString:kDatasourceURLString]
_photos = [[NSDictionary alloc] initWithContentsOfURL:dataSourceURL]
}
return _photos
}
#pragma mark -
#pragma mark - Life cycle
- (void)viewDidLoad {
// 3
self.title = @"Classic Photos"
// 4
self.tableView.rowHeight = 80.0
[super viewDidLoad]
}
- (void)viewDidUnload {
// 5
[self setPhotos:nil]
[super viewDidUnload]
}
#pragma mark -
#pragma mark - UITableView data source and delegate methods
// 6
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger count = self.photos.count
return count
}
// 7
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.0
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellIdentifier = @"Cell Identifier"
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier]
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier]
cell.selectionStyle = UITableViewCellSelectionStyleNone
}
// 8
NSString *rowKey = [[self.photos allKeys] objectAtIndex:indexPath.row]
NSURL *imageURL = [NSURL URLWithString:[self.photos objectForKey:rowKey]]
NSData *imageData = [NSData dataWithContentsOfURL:imageURL]
UIImage *image = nil
// 9
if (imageData) {
UIImage *unfiltered_image = [UIImage imageWithData:imageData]
image = [self applySepiaFilterToImage:unfiltered_image]
}
cell.textLabel.text = rowKey
cell.imageView.image = image
return cell
}
#pragma mark -
#pragma mark - Image filtration
// 10
- (UIImage *)applySepiaFilterToImage:(UIImage *)image {
CIImage *inputImage = [CIImage imageWithData:UIImagePNGRepresentation(image)]
UIImage *sepiaImage = nil
CIContext *context = [CIContext contextWithOptions:nil]
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone" keysAndValues: kCIInputImageKey, inputImage, @"inputIntensity", [NSNumber numberWithFloat:0.8], nil]
CIImage *outputImage = [filter outputImage]
CGImageRef outputImageRef = [context createCGImage:outputImage fromRect:[outputImage extent]]
sepiaImage = [UIImage imageWithCGImage:outputImageRef]
CGImageRelease(outputImageRef)
return sepiaImage
}
@end
上面增加了很多代码,不要惊慌,我们这就来解释一下:
1、Synthesize这个photos实例变量。
2、这里其实是重写了photos的get函数,并且在里面实例化这个数据源对象。
3、设置这个导航栏上的title。
4、设置tableview的行高为80.0
5、当这个ListViewControllerunloaded的时候,设置photos为nil
6、返回这个tableview有多少行
7、这个是UITableViewDelegate的可选的回调方法,然后设置每一行的高度都为80.0,其实每一行默认的44.0的高度。
8、取得这个dictionay的key,然后得到value,就可以得到url了,然后使用nsdata来下载这个图像。
9、加入你已经成功下载这个数据,就可以创建图像,并且可以使用深褐色的滤镜来处理一下。
10、这个方法就是对这个图像使用深褐色的滤镜。假如你想要知道更多关于CoreImagefilters的知识,你可以看看Beginning Core Image in iOS 5 Tutorial。
那下面来试试。编译运行,深褐色图像也出现了,但是似乎他们出现的有点慢。
是时候想想如何提升用户体验了!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)