iOS两丫技术之UILabel性能不够的解决方法

目录
  • Async View
    • Async Layer
    • RunLoop
      • 触发
      • 事件的保存
  • YYLabel

主要参照 YYKit

YYKit 博大精深,就像少林武功

Async View

为了异步 + runloop 空闲时绘制,

因为苹果的 UILabel 性能不够 6

Async Layer

思路: UI 操作,必须放在主线程,

然而图形处理,可以放在子线程,

( 开辟图形上下文,进行绘制,取出图片 )

最后一步,放在主线程,就好了

layer.contents = image

Custom View 中, layer 类,重新制定为异步 layer

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

建立绘制任务

创建一个绘制任务,YYAsyncLayerDisplayTask

关键是里面的绘制方法 display

拿到异步图层 layer 创建的图形上下文,

调一下坐标系,( Core Text 的原点,在左下方 )

文本 map 为富文本,

富文本 map 为一帧,

一帧拆分为好多 CTLine,

一行一行地展示

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    // capture current state to display task
    NSString *text = _text;
    UIFont *fontX = _font;
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    CGFloat h_h = self.bounds.size.height;
    CGFloat w_w = self.bounds.size.width;
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
        //在这里由于绘制文字会颠倒
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            CGContextSetTextMatrix(context, CGAffineTransformIdentity);
            CGContextTranslateCTM(context, 0, h_h);
            CGContextScaleCTM(context, 1.0, -1.0);
        }];
        NSAttributedString* str = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: fontX, NSForegroundColorAttributeName: UIColor.blueColor}];
        CTFramesetterRef ref = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)str);
        CGPathRef path = CGPathCreateWithRect(CGRectMake(0, 0, w_w, 3000), nil);
        CTFrameRef pic = CTFramesetterCreateFrame(ref, CFRangeMake(0, 0), path, nil);
        CFArrayRef arr = CTFrameGetLines(pic);
        NSArray *array = (__bridge NSArray*)arr;
        int i = 0;
        int cnt = (int)array.count;
        CGPoint originsArray[cnt];
        CTFrameGetLineOrigins(pic, CFRangeMake(0, 0), originsArray);
        CGFloat y_y = h_h - 60;
        while (i < cnt) {
            NSLog(@"%f", originsArray[i].y);
            CTLineRef line = (__bridge CTLineRef)(array[i]);
            CGContextSetTextPosition(context, 0, y_y - i * 30);
            CTLineDraw(line, context);
            i += 1;
        }
    };
    return task;
}

Async Layer 中, 启动绘制任务,

先处理下继承关系,

再执行上文提到的绘制任务

- (void)display {
    super.contents = super.contents;
    [self _displayAsync];
}

执行绘制任务,

拿到任务,没有绘制内容,就算了

再判断,自身的大小 ( size ), 合不合规

大小 CGSize(1, 1), 就继续,

子线程,先开辟图形上下文,

再处理背景色,

如果顺利,执行上文的绘制步骤,

从图形上下文中,取出 image, 交给 layer.contents

- (void)_displayAsync{
    __strong id<YYAsyncLayerDelegate> delegate = (id)self.delegate;
    YYAsyncLayerDisplayTask *task = [delegate newAsyncDisplayTask];
    if (!task.display) {
        self.contents = nil;
        return;
    }
        CGSize size = self.bounds.size;
        BOOL opaque = self.opaque;
        CGFloat scale = self.contentsScale;
        CGColorRef backgroundColor = (opaque && self.backgroundColor) ? CGColorRetain(self.backgroundColor) : NULL;
        if (size.width < 1 || size.height < 1) {
            CGImageRef image = (__bridge_retained CGImageRef)(self.contents);
            self.contents = nil;
            if (image) {
                dispatch_async(YYAsyncLayerGetReleaseQueue(), ^{
                    CFRelease(image);
                });
            }
            CGColorRelease(backgroundColor);
            return;
        }
        dispatch_async(YYAsyncLayerGetDisplayQueue(), ^{
            if (isCancelled()) {
                CGColorRelease(backgroundColor);
                return;
            }
            UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
            CGContextRef context = UIGraphicsGetCurrentContext();
            if (opaque) {
                CGContextSaveGState(context); {
                    if (!backgroundColor || CGColorGetAlpha(backgroundColor) < 1) {
                        CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
                        CGContextAddRect(context, CGRectMake(0, 0, size.width * scale, size.height * scale));
                        CGContextFillPath(context);
                    }
                    if (backgroundColor) {
                        CGContextSetFillColorWithColor(context, backgroundColor);
                        CGContextAddRect(context, CGRectMake(0, 0, size.width * scale, size.height * scale));
                        CGContextFillPath(context);
                    }
                } CGContextRestoreGState(context);
                CGColorRelease(backgroundColor);
            }
            task.display(context, size, isCancelled);
            if (isCancelled()) {
                UIGraphicsEndImageContext();
                return;
            }
            UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            if (isCancelled()) {
                return;
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                if (isCancelled() == NO) {
                    self.contents = (__bridge id)(image.CGImage);
                }
            });
        });
}

RunLoop

触发

设置样式后,不会立即触发,重绘

先保存起来

- (void)setText:(NSString *)text {
    _text = text.copy;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

调用异步图层的绘制任务

- (void)contentsNeedUpdated {
    // do update
    [self.layer setNeedsDisplay];
}

事件的保存

先把方法调用的 target 和 action, 保存为对象

YYTransactionSetup(); 单例方法,初始化

把方法调用的对象,添加到集合

@implementation YYTransaction
+ (YYTransaction *)transactionWithTarget:(id)target selector:(SEL)selector{
    if (!target || !selector) return nil;
    YYTransaction *t = [YYTransaction new];
    t.target = target;
    t.selector = selector;
    return t;
}
- (void)commit {
    if (!_target || !_selector) return;
    YYTransactionSetup();
    [transactionSet addObject:self];
}

空闲的时候,把事情给办了,不影响帧率

下面的单例方法,初始化事件任务集合,

run loop 回调中,执行

不干涉, 主 runloop

static NSMutableSet *transactionSet = nil;
static void YYRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    if (transactionSet.count == 0) return;
    NSSet *currentSet = transactionSet;
    transactionSet = [NSMutableSet new];
    [currentSet enumerateObjectsUsingBlock:^(YYTransaction *transaction, BOOL *stop) {
        [transaction.target performSelector:transaction.selector];
    }];
}
static void YYTransactionSetup() {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        transactionSet = [NSMutableSet new];
        CFRunLoopRef runloop = CFRunLoopGetMain();
        CFRunLoopObserverRef observer;
        observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),
                                           kCFRunLoopBeforeWaiting | kCFRunLoopExit,
                                           true,
                                           0xFFFFFF,
                                           YYRunLoopObserverCallBack, NULL);
        CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
        CFRelease(observer);
    });
}

YYLabel

功能相当强大的渲染工具,

在上文异步渲染的基础上

支持各种样式

增加了一层抽象 YYTextLayout

YYLabel 中的绘制任务,

如果需要更新,就创建新的布局 layout ,

如果居中 / 底部对其,处理下 layout 布局

然后 layout 绘制

@implementation YYLabel
- (YYTextAsyncLayerDisplayTask *)newAsyncDisplayTask {
    // create display task
    YYTextAsyncLayerDisplayTask *task = [YYTextAsyncLayerDisplayTask new];
    task.display = ^(CGContextRef context, CGSize size, BOOL (^isCancelled)(void)) {
        if (isCancelled()) return;
        if (text.length == 0) return;
        YYTextLayout *drawLayout = layout;
        if (layoutNeedUpdate) {
            layout = [YYTextLayout layoutWithContainer:container text:text];
            shrinkLayout = [YYLabel _shrinkLayoutWithLayout:layout];
            if (isCancelled()) return;
            layoutUpdated = YES;
            drawLayout = shrinkLayout ? shrinkLayout : layout;
        }
        CGSize boundingSize = drawLayout.textBoundingSize;
        CGPoint point = CGPointZero;
        if (verticalAlignment == YYTextVerticalAlignmentCenter) {
            if (drawLayout.container.isVerticalForm) {
                point.x = -(size.width - boundingSize.width) * 0.5;
            } else {
                point.y = (size.height - boundingSize.height) * 0.5;
            }
        } else if (verticalAlignment == YYTextVerticalAlignmentBottom) {
            if (drawLayout.container.isVerticalForm) {
                point.x = -(size.width - boundingSize.width);
            } else {
                point.y = (size.height - boundingSize.height);
            }
        }
        point = YYTextCGPointPixelRound(point);
        [drawLayout drawInContext:context size:size point:point view:nil layer:nil debug:debug cancel:isCancelled];
    };
    return task;
}
@end

绘制各种

先绘制背景,

其次画阴影,

下划线,

文字,

图片

边框

@implementation YYTextLayout
- (void)drawInContext:(CGContextRef)context
                 size:(CGSize)size
                point:(CGPoint)point
                 view:(UIView *)view
                layer:(CALayer *)layer
                debug:(YYTextDebugOption *)debug
                cancel:(BOOL (^)(void))cancel{
    @autoreleasepool {
        if (self.needDrawBlockBorder && context) {
            if (cancel && cancel()) return;
            YYTextDrawBlockBorder(self, context, size, point, cancel);
        }
        if (self.needDrawBackgroundBorder && context) {
            if (cancel && cancel()) return;
            YYTextDrawBorder(self, context, size, point, YYTextBorderTypeBackgound, cancel);
        }
        if (self.needDrawShadow && context) {
            if (cancel && cancel()) return;
            YYTextDrawShadow(self, context, size, point, cancel);
        }
        if (self.needDrawUnderline && context) {
            if (cancel && cancel()) return;
            YYTextDrawDecoration(self, context, size, point, YYTextDecorationTypeUnderline, cancel);
        }
        if (self.needDrawText && context) {
            if (cancel && cancel()) return;
            YYTextDrawText(self, context, size, point, cancel);
        }
        if (self.needDrawAttachment && (context || view || layer)) {
            if (cancel && cancel()) return;
            YYTextDrawAttachment(self, context, size, point, view, layer, cancel);
        }
        if (self.needDrawInnerShadow && context) {
            if (cancel && cancel()) return;
            YYTextDrawInnerShadow(self, context, size, point, cancel);
        }
        if (self.needDrawStrikethrough && context) {
            if (cancel && cancel()) return;
            YYTextDrawDecoration(self, context, size, point, YYTextDecorationTypeStrikethrough, cancel);
        }
        if (self.needDrawBorder && context) {
            if (cancel && cancel()) return;
            YYTextDrawBorder(self, context, size, point, YYTextBorderTypeNormal, cancel);
        }
        if (debug.needDrawDebug && context) {
            if (cancel && cancel()) return;
            YYTextDrawDebug(self, context, size, point, debug);
        }
    }
}

进入绘制文字

还有图片

这里的绘制粒度,比较上文,

粒度更加的细

上文是 CTLine,

这里是 CTRun

// 注意条件判断,
// 与保存 / 恢复图形上下文
static void YYTextDrawAttachment(YYTextLayout *layout, CGContextRef context, CGSize size, CGPoint point, UIView *targetView, CALayer *targetLayer, BOOL (^cancel)(void)) {
    BOOL isVertical = layout.container.verticalForm;
    CGFloat verticalOffset = isVertical ? (size.width - layout.container.size.width) : 0;
    for (NSUInteger i = 0, max = layout.attachments.count; i < max; i++) {
        YYTextAttachment *a = layout.attachments[i];
        if (!a.content) continue;
        UIImage *image = nil;
        UIView *view = nil;
        CALayer *layer = nil;
        if ([a.content isKindOfClass:[UIImage class]]) {
            image = a.content;
        } else if ([a.content isKindOfClass:[UIView class]]) {
            view = a.content;
        } else if ([a.content isKindOfClass:[CALayer class]]) {
            layer = a.content;
        }
        if (!image && !view && !layer) continue;
        if (image && !context) continue;
        if (view && !targetView) continue;
        if (layer && !targetLayer) continue;
        if (cancel && cancel()) break;
        CGSize asize = image ? image.size : view ? view.frame.size : layer.frame.size;
        CGRect rect = ((NSValue *)layout.attachmentRects[i]).CGRectValue;
        if (isVertical) {
            rect = UIEdgeInsetsInsetRect(rect, UIEdgeInsetRotateVertical(a.contentInsets));
        } else {
            rect = UIEdgeInsetsInsetRect(rect, a.contentInsets);
        }
        rect = YYTextCGRectFitWithContentMode(rect, asize, a.contentMode);
        rect = YYTextCGRectPixelRound(rect);
        rect = CGRectStandardize(rect);
        rect.origin.x += point.x + verticalOffset;
        rect.origin.y += point.y;
        if (image) {
            CGImageRef ref = image.CGImage;
            if (ref) {
                CGContextSaveGState(context);
                CGContextTranslateCTM(context, 0, CGRectGetMaxY(rect) + CGRectGetMinY(rect));
                CGContextScaleCTM(context, 1, -1);
                CGContextDrawImage(context, rect, ref);
                CGContextRestoreGState(context);
            }
        } else if (view) {
            view.frame = rect;
            [targetView addSubview:view];
        } else if (layer) {
            layer.frame = rect;
            [targetLayer addSublayer:layer];
        }
    }
}

本文,最后一个问题:

上面 layout 的绘制信息,怎么取得的?

先拿文本,创建 CTFrame, CTFrame 中拿到 CTLine 数组

然后遍历每一行,与计算

@implementation YYTextLayout
+ (YYTextLayout *)layoutWithContainer:(YYTextContainer *)container text:(NSAttributedString *)text range:(NSRange)range {
    // ...
    ctSetter = CTFramesetterCreateWithAttributedString((CFTypeRef)text);
    if (!ctSetter) goto fail;
    ctFrame = CTFramesetterCreateFrame(ctSetter, YYTextCFRangeFromNSRange(range), cgPath, (CFTypeRef)frameAttrs);
    if (!ctFrame) goto fail;
    lines = [NSMutableArray new];
    ctLines = CTFrameGetLines(ctFrame);
   // ...
   for (NSUInteger i = 0, max = lines.count; i < max; i++) {
        YYTextLine *line = lines[i];
        if (truncatedLine && line.index == truncatedLine.index) line = truncatedLine;
        if (line.attachments.count > 0) {
            [attachments addObjectsFromArray:line.attachments];
            [attachmentRanges addObjectsFromArray:line.attachmentRanges];
            [attachmentRects addObjectsFromArray:line.attachmentRects];
            for (YYTextAttachment *attachment in line.attachments) {
                if (attachment.content) {
                    [attachmentContentsSet addObject:attachment.content];
                }
            }
        }
    }
    // ...
}

github repo

到此这篇关于iOS两丫技术之UILabel性能不够的解决方法的文章就介绍到这了,更多相关iOS UILabe内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • iOS UILabel根据内容自动调整高度

    一.效果图 二.代码 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //根据内容自动调整高度 NSString *str = @"公元前3000年,印度河流域的居民的数字使用就已经比较普遍,居民们采用了十进位制的计算法."; UIFont *font = [UIFont systemFontOfSize:13]; CGSize size = CG

  • iOS如何封装带复制功能的UILabel示例代码

    前言 UILabel继承自UIView是iOS中使用非常频繁的一个视图控件一般用于显示文字. 一:基本使用 1.创建 UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(20, 64, 100, 30)]; [self.view addSubview:label]; 2.属性设置 在iOS中你想要使用一个属性一般就直接"."属性英文名称,或者"set"属性英文名称一般就可以出现 label.backgr

  • iOS动态调整UILabel高度的几种方法

    简介 UILabel类实现了一个只读文本视图.您可以使用这个类来画一个或多个行静态文本,比如你可能使用确定的其他部分的用户界面.UILabel类支持既简单又复杂的样式标签的文本,还可以控制外观,比如标签是否使用一个影子或吸引了一大亮点. 在iOS程序中,看的见.摸得着的,都是UIView的子类.UILabel是一个用于显示文字信息的标签视图类,即UIView的子类. 以下是关于UILabel的官方网址:https://developer.apple.com/reference/uikit/uil

  • iOS中UILabel设置居上对齐、居中对齐、居下对齐及文字置顶显示

    iOS中UILabel设置居上对齐.居中对齐.居下对齐 在iOS中默认的UILabel中的文字在竖直方向上只能居中对齐,博主参考国外网站,从UILabel继承了一个新类,实现了居上对齐,居中对齐,居下对齐. 具体如下: // // myUILabel.h // // // Created by yexiaozi_007 on 3/4/13. // Copyright (c) 2013 yexiaozi_007. All rights reserved. // #import <UIKit/UIK

  • iOS基于 UILabel实现文字添加描边功能

    可以达到文字描一圈黑边的效果: 继承UILabel以后重载drawTextInRect: - (void)drawTextInRect:(CGRect)rect { CGSize shadowOffset = self.shadowOffset; UIColor *textColor = self.textColor; CGContextRef c = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(c, 1); CGContextSet

  • iOS UILabel 设置内容的间距及高度的计算示例

    前言 UILabel 是的使用频率是非常频繁,当文字较多的时候,会显得密密麻麻的,不利于UI显示及用户观看.通常我们需要对 Label 中"行间距"或"文字间距"进行调整,从而使文字没那么紧密,提高用户体验. 当调整"行间距"或"字间距"后,很多时候需要对Label进行高度自适应,此时会出现高度计算错误的问题,所以我们需要对"富文字"高度进行计算.计算结束后,经测试发现:当文字为1行并且全部文字为"

  • iOS中UILabel实现长按复制功能实例代码

    前言 网上有很多种给Label添加长按复制功能的方法,而在 UILabel 上实现长按复制,我用的是 UIMenuController.在 UITextView.UITextField 中,已经自带了这个东西,但是在 UILabel 上需要自定义. 鉴于有的朋友很少接触 UIMenuController,这里先介绍一些基本知识. UIMenuController 可以使用系统自带的方法,也可以自定义. 系统默认支持UITextField.UITextView.UIWebView控件的UIMenu

  • IOS 开发之UILabel 或者 UIButton加下划线链接

    IOS 开发之UILabel 或者 UIButton加下划线链接          本文主要介绍了IOS中 UILable及UIButton的带下划线链接的实现方法及附有源码下载,大家开发IOS 应用有需要的可以参考下: 方法一: NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"查看所有中奖记录"]; NSRange strRange = {0,[str lengt

  • iOS开发总结之UILabel常用属性介绍

    1.text:设置标签显示文本. 2.attributedText:设置标签属性文本. Ios代码 NSString *text = @"first"; NSMutableAttributedString *textLabelStr = [[NSMutableAttributedString alloc] initWithString:text]; [textLabelStr setAttributes:@{NSForegroundColorAttributeName : [UICol

  • AngularJS中update两次出现$promise属性无法识别的解决方法

    前言 本文主要介绍的是在AngularJS中update两次出现$promise属性无法识别的解决方法,下面话不多说,先来看看错误提示,然后再看看解决的办法吧. 一.错误信息如下: ERROR 2015-12-02 14:33:17,653 http-bio-8080-exec-42 o.s.s.r.i.e.InternalErrorExceptionMapper - Unrecognized field "$promise" (class com.inetpsa.fnd.rest.c

  • thinkphp多表查询两表有重复相同字段的完美解决方法

    框架:thinkphp 版本:3.2.3 内容:查询语句 解决问题:重复字段问题 $Data = M('a')->where($where) ->Field('a.name as aname,b.name as uname,a.*') ->join('b on b.jb_id=a.id') ->order('a.id desc') ->select(); 解释:a.* 查询a表所有的字段 a.name as aname 转换a表中的name重复字段为aname 以上就是小编为

  • iOS APP中保存图片到相册时崩溃的解决方法

    环境: iPhone Version 11.0.3 ,  Xcode Version 9.0 问题: 昨天维护APP时,发现拍照后保存图片时应用崩溃,输出如下: This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSPhotoLibraryAddUsageDescr

  • 基于IOS端微信分享失效的踩坑及解决方法

    最近的一个公众号是基于vue的spa应用,在接入微信分享和微信语音的时候出现了:在Android上一切正常,但是在ios端调用wx.config的时候总是失败,去翻了官方文档也并没有找到解决方案,最后在测试中发现是因为初始化的时候传入的URL的问题.具体过程如下: 微信config接口配置,官方文档如下: 所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支

  • ios设备中angularjs无法改变页面title的解决方法

    如下所示: $rootScope.$watch('title',function(title){ var body = document.getElementsByTagName('body')[0]; document.title = title; var iframe = document.createElement("iframe"); iframe.title = ''; iframe.width = 0; iframe.height = 0; iframe.setAttrib

  • iOS App使用GCD导致的卡顿现象及解决方法

    最近在调研 iOS app 中存在的各种卡顿现象以及解决方法. iOS App 出现卡顿(stall)的概率可能超出大部分人的想象,尤其是对于大公司旗舰型 App.一方面是由于业务功能不停累积,各个产品团队之间缺乏协调,大家都忙着增加功能,系统资源出现瓶颈.另一方面的原因是老设备更新换代太慢,iOS 设备的耐用度极好,现在还有不少 iPhone 4S 在服役,iPhone 6 作为问题设备持有量很高,据估计,现在 iPhone 6s 以前的设备占有比高达 40%. 所以,如果尝试在线上 App

  • iOS中Xcode 8 日志输出乱码问题的解决方法

    更新到Xcode 8的同学应该都遇到了这个问题:用Xcode 8运行项目,日志会疯狂的刷,就像下面这种图一样: 日志输出 于是,简单搜寻了下,"歪果仁"给出了如下解决方法: Edit Scheme-> Run -> Arguments, 在Environment Variables里边添加 OS_ACTIVITY_MODE = disable 以上所述是小编给大家介绍的iOS中Xcode 8 日志输出乱码问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复

  • iOS 报clang: error: no input files错误的解决方法

    前言 本文主要给大家介绍了关于解决iOS 报clang: error: no input files错误的方法,这是最近在工作中遇到的一个问题,发现网上的相关解决方法几乎没有,所以将自己的解决过程分享出来,下面话不多说了,来一起看看详细的介绍吧. 一.概念 1.错误描述: ios  clang: error: no input files 2.如图: 二.解决方法 1.文字描述 clang: error: no input files这个问题一般是因为你删除或者移动了某一个文件,但是在你的编译资

  • IOS 签名错误codesign failed with exit code 1解决方法

    IOS 签名错误 前日,Macbook的硬盘不幸挂了,于是将开发环境迁移到Mac Mini下.大家知道,对于Xcode来说,最麻烦的就是各种证书.ProvisioningProfile的配置问题.将原来的各种开发证书和.p12证书导入到mini上,接下来就碰到了各种莫名其妙的问题.先是无法development(可以debug),发现是证书导错了(没有用Agent证书,只有Agent可以发布).于是制作证书请求,重新下载证书. 等到部署的问题解决后,又发现无法调试--真机可以,但模拟器不行,一进

  • 推荐Sql server一些常见性能问题的解决方法

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0 3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放

随机推荐

其他