iOS问题

提示:由于水平有限,如发现有疑问或错误的地方请毫不客气的提出、讨论,我会在第一时间回复,感谢在先

    //给部分 字符串添加删除线不显示. 系统版本为iOS 8.1、10.3
    NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:@"市场价格:"];
    NSAttributedString* priceAtrrStr = [[NSMutableAttributedString alloc]initWithString:@"3.45¥" attributes:@{NsstrikethroughStyleAttributeName : @(NSUnderlinestyleSingle)}];
    [attrStr appendAttributedString:priceAtrrStr];
     _displayLB.attributedText = attrStr;
    //解决方法 
    NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:@"市场价格:" attributes:@{NSBaselineOffsetAttributeName:@0}];
    //@(NSUnderlinestyleNone)  @0值是相同的;
   
  • 价格计算
    NSDecimalNumber继承NSNumber;可以利用NSDecimalNumber计算价格
    // NSDecimalNumber 的利用类属性 来创建对象;
   //@property (class,readonly,copy) NSDecimalNumber *zero;
   //@property (class,copy) NSDecimalNumber *one; 
N<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ring* aPriceStr = @"34.34";
NSDecimalNumber* aDecimal = [NSDecimalNumber decimalNumberWithString:aPriceStr];
N<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ring* bPriceStr = @"34.434";
NSDecimalNumber* bDecimal = [NSDecimalNumber decimalNumberWithString:bPriceStr];
// 加减乘除
NSDecimalNumber* addDecimal =  [aDecimal decimalNumberByAdding:bDecimal];
NSDecimalNumber* subt<a href="https://www.jb51.cc/tag/rating/" target="_blank" class="keywords">rating</a>Decimal =  [aDecimal decimalNumberBySubtracting:bDecimal];
NSDecimalNumber* multiplyingDecimal =  [aDecimal decimalNumberByMultiplyingBy:bDecimal];
NSDecimalNumber* dividingDecimal =  [aDecimal decimalNumberByDividingBy:bDecimal];
// 保留小数点
NSDecimalNumberHandler* behaviors = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoun<a href="https://www.jb51.cc/tag/dpl/" target="_blank" class="keywords">dpl</a>ain scale:2 rai<a href="https://www.jb51.cc/tag/SEO/" title="SEO">SEO</a>nExact<a href="https://www.jb51.cc/tag/nes/" target="_blank" class="keywords">nes</a>s:NO rai<a href="https://www.jb51.cc/tag/SEO/" title="SEO">SEO</a>nOverflow:NO rai<a href="https://www.jb51.cc/tag/SEO/" title="SEO">SEO</a>nUnderflow:NO rai<a href="https://www.jb51.cc/tag/SEO/" title="SEO">SEO</a>nDivideByZero:YES];
NSDecimalNumber* twoPointResult = [addDecimal decimalNumberByRoundingAccordingToBehavior:behaviors];

NSLog(@"addDecimal:%@",addDecimal.stringValue);
NSLog(@"subt<a href="https://www.jb51.cc/tag/rating/" target="_blank" class="keywords">rating</a>Decimal:%@",subt<a href="https://www.jb51.cc/tag/rating/" target="_blank" class="keywords">rating</a>Decimal.stringValue);
NSLog(@"multiplyingDecimal:%@",multiplyingDecimal.stringValue);
NSLog(@"dividingDecimal:%@",dividingDecimal.stringValue);
// 保留两位小数
NSLog(@"twoPointResult:%@",twoPointResult.stringValue);

/*
上面 decimalNumberByDividingBy,decimalNumberByMultiplyingBy,decimalNumberBySubtracting等<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>在实际算计存在安全风险
正确的做法使用各<a href="https://www.jb51.cc/tag/zidai/" target="_blank" class="keywords">自带</a>有behavior的<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

behavior 只要遵循 NSDecimalNumberBehaviors 协议就好.
@protocol NSDecimalNumberBehaviors

- (NSRoundingMode)roundingMode;

- (short)scale; // The scale <a href="https://www.jb51.cc/tag/Could/" target="_blank" class="keywords">Could</a> return NO_SCALE for no defined scale.

- (nullable NSDecimalNumber *)exceptionDuringOperation:(SEL)operation error:(NSCal<a href="https://www.jb51.cc/tag/cula/" target="_blank" class="keywords">cula</a>tionError)error leftOperand:(NSDecimalNumber *)leftOperand rightOperand:(nullable  NSDecimalNumber *)rightOperand;  // Receiver can raise,return a new value,or return nil to ig<a href="https://www.jb51.cc/tag/nor/" target="_blank" class="keywords">nor</a>e the exception.

@end
  @implementation NSDecimalNumberCustomOperBehavior

+ (instancetype)operBehaviorWithRoundingMode:(NSRoundingMode)mode scale:(short)scale {
            NSDecimalNumberCustomOperBehavior* behavior = [[NSDecimalNumberCustomOperBehavior alloc]init];
                behavior.roundingMode = mode;
            behavior.scale = scale;
            return behavior;
}

- (nullable NSDecimalNumber *)exceptionDuringOperation:(SEL)operation error:(NSCal<a href="https://www.jb51.cc/tag/cula/" target="_blank" class="keywords">cula</a>tionError)error leftOperand:(NSDecimalNumber *)leftOperand rightOperand:(nullable NSDecimalNumber *)rightOperand {
        //处理异常
        return [NSDecimalNumber notANumber];
}

- (NSRoundingMode)roundingMode {
        //舍入模式
           return _roundingMode;
}

- (short)scale {
        //小数点精度
        return _scale;
}

@end

系统<a href="https://www.jb51.cc/tag/mo/" target="_blank" class="keywords">默</a>认提供 <a href="https://www.jb51.cc/tag/yige/" target="_blank" class="keywords">一个</a> NSDecimalNumberHandler类也是遵循  NSDecimalNumberBehaviors协议的.

*/

/
addDecimal:68.774
subtratingDecimal:-0.094
multiplyingDecimal:1182.46356
dividingDecimal:0.9972701399779287913109136318754719172
twoPointResult:68.77
/
/* RoundingMode 含义

Original Value  NSRoun<a href="https://www.jb51.cc/tag/dpl/" target="_blank" class="keywords">dpl</a>ain  NSRoundDown &amp; NS RoundUp    NSRoundBankers
1.24            1.2                 1.2 &amp; 1.3                  1.2
1.26            1.3                 1.2 &amp; 1.3                  1.3
1.25            1.3                 1.2 &amp; 1.3                  1.2
1.35            1.4                 1.3 &amp; 1.4                  1.4
–1.35           –1.4                –1.4 &amp; -1.3                –1.4

NSRoun<a href="https://www.jb51.cc/tag/dpl/" target="_blank" class="keywords">dpl</a>ain: 取最接近的数;如果最后一位为5;为正数时向上取值,为负数时向下取值
NSRoundDown: 向下值
NSRoundUp: 向上值
NSRoundBankers:取最接近的数;如果最后一位为5;通过向上或者向下取值使得取值后最后<a href="https://www.jb51.cc/tag/yige/" target="_blank" class="keywords">一个</a>数为偶数
*/

(1)instrumentObjcMessageSends(YES); // 开启 instrumentObjcMessageSends(NO); //关闭 使用的时候需要添加函数声明extern instrumentObjcMessageSends(BOOL); log保存在 /tmp/msg-xxxx 的文件中(只能在模拟器中使用哦)

 #import 
 typedef void(*func)(BOOL);
   static inline void ste_tracing_msg(BOOL yesOrNo) {
   void* libObj = dlopen("/usr/lib/libobjc.dylib",RTLD_LAZY);
   func instrumentObjcMessageSends = dlsym(libObj,"instrumentObjcMessageSends");
   instrumentObjcMessageSends(yesOrNo);
   //同上面相同,log保存在 /tmp/msg-xxxx
}

(2)设置NSObjCMessageLoggingEnabled 环境变量可以打印所有message,log保存在 /tmp/msg-xxxx 的文件中;由于内容很多,查看的时候需要用vim 进行搜索

  • 为带有XIB的ViewController减负;
    对于简单界面而言;控件都放在xib上,然后把xib上的创建的不同View outLet 对应的view上面就可以了.
  • NSObject load vs initialize;

load
Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.
无论何时,当一个类或者类目添加到runtime中时,在这个类或者类目加载的过程中,实现的load方法就可以执行一些和类相关的业务逻辑. (重点:何时 + 做什么)
load order
A class’s +load method is called after all of its superclasses’ +load methods.
A category +load method is called after the class’s own +load method.
总结来说加载顺序就是: superclasse’+load ->classes’ + load -> category’ + load

  void call_load_methods(void)
{
    static BOOL loading = NO;
    BOOL more_categories;
recursive_mutex_assert_locked(&amp;loadMethodLock);

// Re-entrant calls do nothing; the outermost call will finish the job.
if (loading) return;
loading = YES;

void *pool = objc_autoreleasePoolPush();

do {
     //从下面的顺序中可以看到,是先加载类的load方法,然后再加载category的load方法
    // 1. Repeatedly call class +loads until there aren't any more
    while (loadable_classes_used > 0) {
        call_class_loads(); //分别调用class load方法
    }

    // 2. Call category +loads ONCE
    more_categories = call_category_loads(); //调用类目的加载方法;

    // 3. Run more +loads if there are classes OR more untried categories
} while (loadable_classes_used > 0  ||  more_categories);

objc_autoreleasePoolPop(pool);

loading = NO;

}

static void schedule_class_load(class_t *cls)
{
if (!cls) return;
assert(isRealized(cls)); // _read_images should realize

if (cls->data()->flags &amp; RW_LOADED) return;

// Ensure superclass-first ordering
schedule_class_load(getSuperclass(cls)); //确保父类的load方法先加载

add_class_to_loadable_list((Class)cls);
changeInfo(cls,RW_LOADED,0); 

}

需要注意的地方: In a custom implementation of load you can therefore safely message other unrelated classes from the same image,but any load methods implemented by those classes may not have run yet (假设一个镜像文件中有 A类、A类的父类、A类类目,B类、B类的父类、B类类目,我们唯一能确定的是:先加载一个类(A或者B其中一个)的父类然后再加载这个类(A或者B),我们无法确认是先加载A类还是B类)

initialize :Initializes the class before it receives its first message. 在对象接受到第一条消息之前执行initialize方法,但是注意 __这里message不包括load__;load的方法是在加载时执行的,在initialize执行之前.并且执行一次;因为使用的时候,如果一个类没有实现initialize方法,它就会调用父类的initialize的方法(如果父类实现这个方法的话),为了减少不必要的判断关系,我们一般使用load

void _class_initialize(Class cls)
{  
    //摘取的代码片段
    assert(!_class_isMetaClass(cls));
    Class supercls;
    BOOL reallyInitialize = NO;
    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // See note about deadlock above.
    supercls = _class_getSuperclass(cls);
    // 先initialize父类
    if (supercls  &&  !_class_isInitialized(supercls)) {
        _class_initialize(supercls);
    }
    // initialize本类
    // Try to atomically set CLS_INITIALIZING.
    if (!_class_isInitialized(cls) && !_class_isInitializing(cls)) {
        _class_setInitializing(cls);
        reallyInitialize = YES;
    }
}

需要的注意的是: The superclass implementation may be called multiple times if subclasses do not implement initialize—the runtime will call the inherited implementation—or if subclasses explicitly call [super initialize] If you want to protect yourself from being run multiple times,you can structure your implementation along these lines:

+ (void)initialize {
  //判断是本类就执行相应的方法.
  if (self == [ClassName self]) {
    // ... do the initialization ...
  }
}

另外一点要注意的是如果 在category也实现了initialize方法 那么父类的initialize估计要被覆盖了,个人 猜测是因为category加载时机在类的后面(gusess ) .其实 initialize方法基本和一般方法使用相同
load 和 initialize中方法应该只执行 轻量级的任务

参考内容链接:


相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...