This commit is contained in:
2025-10-28 10:18:10 +08:00
parent efb04d134e
commit 1deca2ae5b
166 changed files with 17288 additions and 1427 deletions

View File

@@ -0,0 +1,23 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// CALayer+Lookin.h
// Lookin
//
// Created by Li Kai on 2018/8/4.
// https://lookin.work
//
#import "LookinDefines.h"
#import <QuartzCore/QuartzCore.h>
@interface CALayer (Lookin)
- (void)lookin_removeImplicitAnimations;
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,70 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// CALayer+Lookin.m
// Lookin
//
// Created by Li Kai on 2018/8/4.
// https://lookin.work
//
#import "CALayer+Lookin.h"
@implementation CALayer (Lookin)
- (void)lookin_removeImplicitAnimations {
NSMutableDictionary<NSString *, id<CAAction>> *actions = @{NSStringFromSelector(@selector(bounds)): [NSNull null],
NSStringFromSelector(@selector(position)): [NSNull null],
NSStringFromSelector(@selector(zPosition)): [NSNull null],
NSStringFromSelector(@selector(anchorPoint)): [NSNull null],
NSStringFromSelector(@selector(anchorPointZ)): [NSNull null],
NSStringFromSelector(@selector(transform)): [NSNull null],
NSStringFromSelector(@selector(sublayerTransform)): [NSNull null],
NSStringFromSelector(@selector(masksToBounds)): [NSNull null],
NSStringFromSelector(@selector(contents)): [NSNull null],
NSStringFromSelector(@selector(contentsRect)): [NSNull null],
NSStringFromSelector(@selector(contentsScale)): [NSNull null],
NSStringFromSelector(@selector(contentsCenter)): [NSNull null],
NSStringFromSelector(@selector(minificationFilterBias)): [NSNull null],
NSStringFromSelector(@selector(backgroundColor)): [NSNull null],
NSStringFromSelector(@selector(cornerRadius)): [NSNull null],
NSStringFromSelector(@selector(borderWidth)): [NSNull null],
NSStringFromSelector(@selector(borderColor)): [NSNull null],
NSStringFromSelector(@selector(opacity)): [NSNull null],
NSStringFromSelector(@selector(compositingFilter)): [NSNull null],
NSStringFromSelector(@selector(filters)): [NSNull null],
NSStringFromSelector(@selector(backgroundFilters)): [NSNull null],
NSStringFromSelector(@selector(shouldRasterize)): [NSNull null],
NSStringFromSelector(@selector(rasterizationScale)): [NSNull null],
NSStringFromSelector(@selector(shadowColor)): [NSNull null],
NSStringFromSelector(@selector(shadowOpacity)): [NSNull null],
NSStringFromSelector(@selector(shadowOffset)): [NSNull null],
NSStringFromSelector(@selector(shadowRadius)): [NSNull null],
NSStringFromSelector(@selector(shadowPath)): [NSNull null]}.mutableCopy;
if ([self isKindOfClass:[CAShapeLayer class]]) {
[actions addEntriesFromDictionary:@{NSStringFromSelector(@selector(path)): [NSNull null],
NSStringFromSelector(@selector(fillColor)): [NSNull null],
NSStringFromSelector(@selector(strokeColor)): [NSNull null],
NSStringFromSelector(@selector(strokeStart)): [NSNull null],
NSStringFromSelector(@selector(strokeEnd)): [NSNull null],
NSStringFromSelector(@selector(lineWidth)): [NSNull null],
NSStringFromSelector(@selector(miterLimit)): [NSNull null],
NSStringFromSelector(@selector(lineDashPhase)): [NSNull null]}];
}
if ([self isKindOfClass:[CAGradientLayer class]]) {
[actions addEntriesFromDictionary:@{NSStringFromSelector(@selector(colors)): [NSNull null],
NSStringFromSelector(@selector(locations)): [NSNull null],
NSStringFromSelector(@selector(startPoint)): [NSNull null],
NSStringFromSelector(@selector(endPoint)): [NSNull null]}];
}
self.actions = actions;
}
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,27 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// Color+Lookin.h
// LookinShared
//
// Created by 李凯 on 2022/4/2.
//
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
@interface NSColor (Lookin)
+ (instancetype)lookin_colorFromRGBAComponents:(NSArray<NSNumber *> *)components;
- (NSArray<NSNumber *> *)lookin_rgbaComponents;
@end
#endif
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,42 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// Color+Lookin.m
// LookinShared
//
// Created by on 2022/4/2.
//
#import "Image+Lookin.h"
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
@implementation NSColor (Lookin)
+ (instancetype)lookin_colorFromRGBAComponents:(NSArray<NSNumber *> *)components {
if (!components) {
return nil;
}
if (components.count != 4) {
NSAssert(NO, @"");
return nil;
}
NSColor *color = [NSColor colorWithRed:components[0].doubleValue green:components[1].doubleValue blue:components[2].doubleValue alpha:components[3].doubleValue];
return color;
}
- (NSArray<NSNumber *> *)lookin_rgbaComponents {
NSColor *rgbColor = [self colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
CGFloat r, g, b, a;
[rgbColor getRed:&r green:&g blue:&b alpha:&a];
NSArray<NSNumber *> *rgba = @[@(r), @(g), @(b), @(a)];
return rgba;
}
@end
#endif
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,25 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// Image+Lookin.h
// LookinShared
//
// Created by 李凯 on 2022/4/2.
//
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
@interface NSImage (LookinClient)
- (NSData *)lookin_data;
@end
#endif
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,26 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// Image+Lookin.m
// LookinShared
//
// Created by on 2022/4/2.
//
#import "Image+Lookin.h"
#if TARGET_OS_IPHONE
#elif TARGET_OS_MAC
@implementation NSImage (LookinClient)
- (NSData *)lookin_data {
return [self TIFFRepresentation];
}
@end
#endif
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,72 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSArray+Lookin.h
// Lookin
//
// Created by Li Kai on 2018/9/3.
// https://lookin.work
//
#import "LookinDefines.h"
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
@interface NSArray<__covariant ValueType> (Lookin)
/**
初始化一个新的 NSArray 并返回,新数组的长度为 count如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则会舍弃多余的元素,被舍弃的元素会作为参数传入 removeBlock。最终新数组的所有元素均会作为参数被传入 doBlock。
*/
- (NSArray<ValueType> *)lookin_resizeWithCount:(NSUInteger)count add:(ValueType (^)(NSUInteger idx))addBlock remove:(void (^)(NSUInteger idx, ValueType obj))removeBlock doNext:(void (^)(NSUInteger idx, ValueType obj))doBlock __attribute__((warn_unused_result));
+ (NSArray *)lookin_arrayWithCount:(NSUInteger)count block:(id (^)(NSUInteger idx))block;
/**
检查 index 位置是否有元素存在
*/
- (BOOL)lookin_hasIndex:(NSInteger)index;
- (NSArray *)lookin_map:(id (^)(NSUInteger idx, ValueType value))block;
- (NSArray<ValueType> *)lookin_filter:(BOOL (^)( ValueType obj))block;
- (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block;
/// 返回最后一个 block 返回 YES 的元素
- (ValueType)lookin_lastFiltered:(BOOL (^)(ValueType obj))block;
- (id)lookin_reduce:(id (^)(id accumulator, NSUInteger idx, ValueType obj))block;
- (CGFloat)lookin_reduceCGFloat:(CGFloat (^)(CGFloat accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(CGFloat)initialAccumlator;
- (NSInteger)lookin_reduceInteger:(NSInteger (^)(NSInteger accumulator, NSUInteger idx, ValueType obj))block initialAccumlator:(NSInteger)initialAccumlator;
- (BOOL)lookin_all:(BOOL (^)(ValueType obj))block;
- (BOOL)lookin_any:(BOOL (^)(ValueType obj))block;
- (NSArray<ValueType> *)lookin_arrayByRemovingObject:(ValueType)obj;
- (NSArray<ValueType> *)lookin_nonredundantArray;
- (ValueType)lookin_safeObjectAtIndex:(NSInteger)idx;
/// 字符串长度从短到长,即 length 小的字符串的 idx 更小
- (NSArray<ValueType> *)lookin_sortedArrayByStringLength;
@end
@interface NSMutableArray<ValueType> (Lookin)
/**
如果当前数组长度比 count 小则会补充新元素(被补充的元素由 addBlock 返回),如果当前数组长度比 count 大则多余的元素会被作为参数传入 notDequeued。然后从 idx 为 0 算起,前 count 个元素会被作为参数传入 doBlock
*/
- (void)lookin_dequeueWithCount:(NSUInteger)count add:(ValueType (^)(NSUInteger idx))addBlock notDequeued:(void (^)(NSUInteger idx, ValueType obj))notDequeuedBlock doNext:(void (^)(NSUInteger idx, ValueType obj))doBlock;
- (void)lookin_removeObjectsPassingTest:(BOOL (^)(NSUInteger idx, ValueType obj))block;
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,300 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSArray+Lookin.m
// Lookin
//
// Created by Li Kai on 2018/9/3.
// https://lookin.work
//
#import "NSArray+Lookin.h"
@implementation NSArray (Lookin)
- (NSArray *)lookin_resizeWithCount:(NSUInteger)count add:(id (^)(NSUInteger idx))addBlock remove:(void (^)(NSUInteger idx, id obj))removeBlock doNext:(void (^)(NSUInteger idx, id obj))doBlock {
NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:count];
for (NSUInteger i = 0; i < count; i++) {
if (self.count > i) {
id obj = [self objectAtIndex:i];
[resultArray addObject:obj];
if (doBlock) {
doBlock(i, obj);
}
} else {
if (addBlock) {
id newObj = addBlock(i);
if (newObj) {
[resultArray addObject:newObj];
if (doBlock) {
doBlock(i, newObj);
}
} else {
NSAssert(NO, @"");
}
} else {
NSAssert(NO, @"");
}
}
}
if (removeBlock) {
if (self.count > count) {
for (NSUInteger i = count; i < self.count; i++) {
id obj = [self objectAtIndex:i];
removeBlock(i, obj);
}
}
}
return [resultArray copy];
}
+ (NSArray *)lookin_arrayWithCount:(NSUInteger)count block:(id (^)(NSUInteger idx))block {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
for (NSUInteger i = 0; i < count; i++) {
id obj = block(i);
if (obj) {
[array addObject:obj];
}
}
return [array copy];
}
- (BOOL)lookin_hasIndex:(NSInteger)index {
if (index == NSNotFound || index < 0) {
return NO;
}
return self.count > index;
}
- (NSArray *)lookin_map:(id (^)(NSUInteger , id))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
id newObj = block(idx, obj);
if (newObj) {
[array addObject:newObj];
}
}];
return [array copy];
}
- (NSArray *)lookin_filter:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
NSMutableArray *mArray = [NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (block(obj)) {
[mArray addObject:obj];
}
}];
return [mArray copy];
}
- (id)lookin_firstFiltered:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
__block id targetObj = nil;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (block(obj)) {
targetObj = obj;
*stop = YES;
}
}];
return targetObj;
}
- (id)lookin_lastFiltered:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
__block id targetObj = nil;
[self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (block(obj)) {
targetObj = obj;
*stop = YES;
}
}];
return targetObj;
}
- (id)lookin_reduce:(id (^)(id accumulator, NSUInteger idx, id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
__block id accumulator = nil;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
accumulator = block(accumulator, idx, obj);
}];
return accumulator;
}
- (CGFloat)lookin_reduceCGFloat:(CGFloat (^)(CGFloat accumulator, NSUInteger idx, id obj))block initialAccumlator:(CGFloat)initialAccumlator {
if (!block) {
NSAssert(NO, @"");
return initialAccumlator;
}
__block CGFloat accumulator = initialAccumlator;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
accumulator = block(accumulator, idx, obj);
}];
return accumulator;
}
- (NSInteger)lookin_reduceInteger:(NSInteger (^)(NSInteger, NSUInteger, id))block initialAccumlator:(NSInteger)initialAccumlator {
if (!block) {
NSAssert(NO, @"");
return initialAccumlator;
}
__block NSInteger accumulator = initialAccumlator;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
accumulator = block(accumulator, idx, obj);
}];
return accumulator;
}
- (BOOL)lookin_all:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return NO;
}
__block BOOL allPass = YES;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL boolValue = block(obj);
if (!boolValue) {
allPass = NO;
*stop = YES;
}
}];
return allPass;
}
- (BOOL)lookin_any:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return NO;
}
__block BOOL anyPass = NO;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL boolValue = block(obj);
if (boolValue) {
anyPass = YES;
*stop = YES;
}
}];
return anyPass;
}
- (NSArray *)lookin_arrayByRemovingObject:(id)obj {
if (!obj || ![self containsObject:obj]) {
return self;
}
NSMutableArray *mutableArray = self.mutableCopy;
[mutableArray removeObject:obj];
return mutableArray.copy;
}
- (NSArray *)lookin_nonredundantArray {
NSSet *set = [NSSet setWithArray:self];
NSArray *newArray = [set allObjects];
return newArray;
}
- (id)lookin_safeObjectAtIndex:(NSInteger)idx {
if (idx == NSNotFound || idx < 0) {
return nil;
}
if (self.count <= idx) {
return nil;
}
return [self objectAtIndex:idx];
}
- (NSArray *)lookin_sortedArrayByStringLength {
NSArray<NSString *> *sortedArray = [self sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
if (obj1.length > obj2.length) {
return NSOrderedDescending;
} else if (obj1.length == obj2.length) {
return NSOrderedSame;
} else {
return NSOrderedAscending;
}
}];
return sortedArray;
}
@end
@implementation NSMutableArray (Lookin)
- (void)lookin_dequeueWithCount:(NSUInteger)count add:(id (^)(NSUInteger idx))addBlock notDequeued:(void (^)(NSUInteger idx, id obj))notDequeuedBlock doNext:(void (^)(NSUInteger idx, id obj))doBlock {
for (NSUInteger i = 0; i < count; i++) {
if ([self lookin_hasIndex:i]) {
id obj = [self objectAtIndex:i];
if (doBlock) {
doBlock(i, obj);
}
} else {
if (addBlock) {
id newObj = addBlock(i);
if (newObj) {
[self addObject:newObj];
if (doBlock) {
doBlock(i, newObj);
}
} else {
NSAssert(NO, @"");
}
} else {
NSAssert(NO, @"");
}
}
}
if (notDequeuedBlock) {
if (self.count > count) {
for (NSUInteger i = count; i < self.count; i++) {
id obj = [self objectAtIndex:i];
notDequeuedBlock(i, obj);
}
}
}
}
- (void)lookin_removeObjectsPassingTest:(BOOL (^)(NSUInteger idx, id obj))block {
if (!block) {
return;
}
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
[self enumerateObjectsUsingBlock:^(id _Nonnull currentObj, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL boolValue = block(idx, currentObj);
if (boolValue) {
[indexSet addIndex:idx];
}
}];
[self removeObjectsAtIndexes:indexSet];
}
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,108 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSObject+Lookin.h
// Lookin
//
// Created by Li Kai on 2018/12/22.
// https://lookin.work
//
#import "LookinDefines.h"
#import <Foundation/Foundation.h>
#import "LookinCodingValueType.h"
@interface NSObject (Lookin)
#pragma mark - Data Bind
/**
给对象绑定上另一个对象以供后续取出使用,如果 object 传入 nil 则会清除该 key 之前绑定的对象
@attention 被绑定的对象会被 strong 强引用
@note 内部是使用 objc_setAssociatedObject / objc_getAssociatedObject 来实现
@code
- (UITableViewCell *)cellForIndexPath:(NSIndexPath *)indexPath {
// 1在这里给 button 绑定上 indexPath 对象
[cell lookin_bindObject:indexPath forKey:@"indexPath"];
}
- (void)didTapButton:(UIButton *)button {
// 2在这里取出被点击的 button 的 indexPath 对象
NSIndexPath *indexPathTapped = [button lookin_getBindObjectForKey:@"indexPath"];
}
@endcode
*/
- (void)lookin_bindObject:(id)object forKey:(NSString *)key;
/**
给对象绑定上另一个对象以供后续取出使用,但相比于 lookin_bindObject:forKey:,该方法不会 strong 强引用传入的 object
*/
- (void)lookin_bindObjectWeakly:(id)object forKey:(NSString *)key;
/**
取出之前使用 bind 方法绑定的对象
*/
- (id)lookin_getBindObjectForKey:(NSString *)key;
/**
给对象绑定上一个 double 值以供后续取出使用
*/
- (void)lookin_bindDouble:(double)doubleValue forKey:(NSString *)key;
/**
取出之前用 lookin_bindDouble:forKey: 绑定的值
*/
- (double)lookin_getBindDoubleForKey:(NSString *)key;
/**
给对象绑定上一个 BOOL 值以供后续取出使用
*/
- (void)lookin_bindBOOL:(BOOL)boolValue forKey:(NSString *)key;
/**
取出之前用 lookin_bindBOOL:forKey: 绑定的值
*/
- (BOOL)lookin_getBindBOOLForKey:(NSString *)key;
/**
给对象绑定上一个 long 值以供后续取出使用
*/
- (void)lookin_bindLong:(long)longValue forKey:(NSString *)key;
/**
取出之前用 lookin_bindLong:forKey: 绑定的值
*/
- (long)lookin_getBindLongForKey:(NSString *)key;
/**
给对象绑定上一个 CGPoint 值以供后续取出使用
*/
- (void)lookin_bindPoint:(CGPoint)pointValue forKey:(NSString *)key;
/**
取出之前用 lookin_bindPoint:forKey: 绑定的值
*/
- (CGPoint)lookin_getBindPointForKey:(NSString *)key;
/**
移除之前使用 bind 方法绑定的对象
*/
- (void)lookin_clearBindForKey:(NSString *)key;
@end
@interface NSObject (Lookin_Coding)
/// 会把 NSImage/UIImage 转换为 NSData把 NSColor/UIColor 转换回 NSNumber 数组(rgba)
- (id)lookin_encodedObjectWithType:(LookinCodingValueType)type;
/// 会把 NSData 转换回 NSImage/UIImage把 NSNumber 数组(rgba) 转换为 NSColor/UIColor
- (id)lookin_decodedObjectWithType:(LookinCodingValueType)type;
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,238 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSObject+Lookin.m
// Lookin
//
// Created by Li Kai on 2018/12/22.
// https://lookin.work
//
#import "NSObject+Lookin.h"
#import <objc/runtime.h>
#import "TargetConditionals.h"
#import "LookinWeakContainer.h"
@implementation NSObject (Lookin)
#pragma mark - Data Bind
static char kAssociatedObjectKey_LookinAllBindObjects;
- (NSMutableDictionary<id, id> *)lookin_allBindObjects {
NSMutableDictionary<id, id> *dict = objc_getAssociatedObject(self, &kAssociatedObjectKey_LookinAllBindObjects);
if (!dict) {
dict = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &kAssociatedObjectKey_LookinAllBindObjects, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return dict;
}
- (void)lookin_bindObject:(id)object forKey:(NSString *)key {
if (!key.length) {
NSAssert(NO, @"");
return;
}
@synchronized (self) {
if (object) {
[[self lookin_allBindObjects] setObject:object forKey:key];
} else {
[[self lookin_allBindObjects] removeObjectForKey:key];
}
}
}
- (id)lookin_getBindObjectForKey:(NSString *)key {
if (!key.length) {
NSAssert(NO, @"");
return nil;
}
@synchronized (self) {
id storedObj = [[self lookin_allBindObjects] objectForKey:key];
if ([storedObj isKindOfClass:[LookinWeakContainer class]]) {
storedObj = [(LookinWeakContainer *)storedObj object];
}
return storedObj;
}
}
- (void)lookin_bindObjectWeakly:(id)object forKey:(NSString *)key {
if (!key.length) {
NSAssert(NO, @"");
return;
}
if (object) {
LookinWeakContainer *container = [[LookinWeakContainer alloc] init];
container.object = object;
[self lookin_bindObject:container forKey:key];
} else {
[self lookin_bindObject:nil forKey:key];
}
}
- (void)lookin_bindDouble:(double)doubleValue forKey:(NSString *)key {
[self lookin_bindObject:@(doubleValue) forKey:key];
}
- (double)lookin_getBindDoubleForKey:(NSString *)key {
id object = [self lookin_getBindObjectForKey:key];
if ([object isKindOfClass:[NSNumber class]]) {
double doubleValue = [(NSNumber *)object doubleValue];
return doubleValue;
} else {
return 0.0;
}
}
- (void)lookin_bindBOOL:(BOOL)boolValue forKey:(NSString *)key {
[self lookin_bindObject:@(boolValue) forKey:key];
}
- (BOOL)lookin_getBindBOOLForKey:(NSString *)key {
id object = [self lookin_getBindObjectForKey:key];
if ([object isKindOfClass:[NSNumber class]]) {
BOOL boolValue = [(NSNumber *)object boolValue];
return boolValue;
} else {
return NO;
}
}
- (void)lookin_bindLong:(long)longValue forKey:(NSString *)key {
[self lookin_bindObject:@(longValue) forKey:key];
}
- (long)lookin_getBindLongForKey:(NSString *)key {
id object = [self lookin_getBindObjectForKey:key];
if ([object isKindOfClass:[NSNumber class]]) {
long longValue = [(NSNumber *)object longValue];
return longValue;
} else {
return 0;
}
}
- (void)lookin_bindPoint:(CGPoint)pointValue forKey:(NSString *)key {
#if TARGET_OS_IPHONE
[self lookin_bindObject:[NSValue valueWithCGPoint:pointValue] forKey:key];
#elif TARGET_OS_MAC
NSPoint nsPoint = NSMakePoint(pointValue.x, pointValue.y);
[self lookin_bindObject:[NSValue valueWithPoint:nsPoint] forKey:key];
#endif
}
- (CGPoint)lookin_getBindPointForKey:(NSString *)key {
id object = [self lookin_getBindObjectForKey:key];
if ([object isKindOfClass:[NSValue class]]) {
#if TARGET_OS_IPHONE
CGPoint pointValue = [(NSValue *)object CGPointValue];
#elif TARGET_OS_MAC
NSPoint nsPointValue = [(NSValue *)object pointValue];
CGPoint pointValue = CGPointMake(nsPointValue.x, nsPointValue.y);
#endif
return pointValue;
} else {
return CGPointZero;
}
}
- (void)lookin_clearBindForKey:(NSString *)key {
[self lookin_bindObject:nil forKey:key];
}
@end
@implementation NSObject (Lookin_Coding)
- (id)lookin_encodedObjectWithType:(LookinCodingValueType)type {
if (type == LookinCodingValueTypeColor) {
if ([self isKindOfClass:[LookinColor class]]) {
CGFloat r, g, b, a;
#if TARGET_OS_IPHONE
CGFloat white;
if ([(UIColor *)self getRed:&r green:&g blue:&b alpha:&a]) {
// valid
} else if ([(UIColor *)self getWhite:&white alpha:&a]) {
r = white;
g = white;
b = white;
} else {
NSAssert(NO, @"");
r = 0;
g = 0;
b = 0;
a = 0;
}
#elif TARGET_OS_MAC
NSColor *color = [((NSColor *)self) colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
[color getRed:&r green:&g blue:&b alpha:&a];
#endif
NSArray<NSNumber *> *rgba = @[@(r), @(g), @(b), @(a)];
return rgba;
} else {
NSAssert(NO, @"");
return nil;
}
} else if (type == LookinCodingValueTypeImage) {
#if TARGET_OS_IPHONE
if ([self isKindOfClass:[UIImage class]]) {
UIImage *image = (UIImage *)self;
return UIImagePNGRepresentation(image);
} else {
NSAssert(NO, @"");
return nil;
}
#elif TARGET_OS_MAC
if ([self isKindOfClass:[NSImage class]]) {
NSImage *image = (NSImage *)self;
return [image TIFFRepresentation];
} else {
NSAssert(NO, @"");
return nil;
}
#endif
} else {
return self;
}
}
- (id)lookin_decodedObjectWithType:(LookinCodingValueType)type {
if (type == LookinCodingValueTypeColor) {
if ([self isKindOfClass:[NSArray class]]) {
NSArray<NSNumber *> *rgba = (NSArray *)self;
CGFloat r = [rgba[0] doubleValue];
CGFloat g = [rgba[1] doubleValue];
CGFloat b = [rgba[2] doubleValue];
CGFloat a = [rgba[3] doubleValue];
LookinColor *color = [LookinColor colorWithRed:r green:g blue:b alpha:a];
return color;
} else {
NSAssert(NO, @"");
return nil;
}
} else if (type == LookinCodingValueTypeImage) {
if ([self isKindOfClass:[NSData class]]) {
LookinImage *image = [[LookinImage alloc] initWithData:(NSData *)self];
return image;
} else {
NSAssert(NO, @"");
return nil;
}
} else {
return self;
}
}
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,39 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSSet+Lookin.h
// Lookin
//
// Created by Li Kai on 2019/1/13.
// https://lookin.work
//
#import "LookinDefines.h"
#import "TargetConditionals.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#elif TARGET_OS_MAC
#import <Appkit/Appkit.h>
#endif
@interface NSSet<__covariant ValueType> (Lookin)
- (NSSet *)lookin_map:(id (^)(ValueType obj))block;
- (ValueType)lookin_firstFiltered:(BOOL (^)(ValueType obj))block;
- (NSSet<ValueType> *)lookin_filter:(BOOL (^)(ValueType obj))block;
/**
是否有任何一个元素满足某条件
@note 元素将被依次传入 block 里,如果任何一个 block 返回 YES则该方法返回 YES。如果所有 block 均返回 NO则该方法返回 NO。
*/
- (BOOL)lookin_any:(BOOL (^)(ValueType obj))block;
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,81 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSSet+Lookin.m
// Lookin
//
// Created by Li Kai on 2019/1/13.
// https://lookin.work
//
#import "NSSet+Lookin.h"
@implementation NSSet (Lookin)
- (NSSet *)lookin_map:(id (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
NSMutableSet *newSet = [NSMutableSet setWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
id newObj = block(obj);
if (newObj) {
[newSet addObject:newObj];
}
}];
return [newSet copy];
}
- (id)lookin_firstFiltered:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
__block id targetObj = nil;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
if (block(obj)) {
targetObj = obj;
*stop = YES;
}
}];
return targetObj;
}
- (NSSet *)lookin_filter:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return nil;
}
NSMutableSet *mSet = [NSMutableSet set];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
if (block(obj)) {
[mSet addObject:obj];
}
}];
return [mSet copy];
}
- (BOOL)lookin_any:(BOOL (^)(id obj))block {
if (!block) {
NSAssert(NO, @"");
return NO;
}
__block BOOL boolValue = NO;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
if (block(obj)) {
boolValue = YES;
*stop = YES;
}
}];
return boolValue;
}
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,42 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSString+Lookin.h
// Lookin
//
// Created by Li Kai on 2019/5/11.
// https://lookin.work
//
#import "LookinDefines.h"
#import <Foundation/Foundation.h>
@interface NSString (Lookin)
/**
把 CGFloat 转成字符串,最多保留 3 位小数,转换后末尾的 0 会被删除
1.2341 => @"1.234", 2.1002 => @"2.1", 3.000 => @"3"
*/
+ (NSString *)lookin_stringFromDouble:(double)doubleValue decimal:(NSUInteger)decimal;
+ (NSString *)lookin_stringFromRect:(CGRect)rect;
+ (NSString *)lookin_stringFromInset:(LookinInsets)insets;
+ (NSString *)lookin_stringFromSize:(CGSize)size;
+ (NSString *)lookin_stringFromPoint:(CGPoint)point;
+ (NSString *)lookin_rgbaStringFromColor:(LookinColor *)color;
- (NSString *)lookin_safeInitWithUTF8String:(const char *)string;
/// 把 1.2.3 这种 String 版本号转换成数字,可用于大小比较,如 110205 代表 11.2.5 版本
- (NSInteger)lookin_numbericOSVersion;
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */

View File

@@ -0,0 +1,117 @@
#ifdef SHOULD_COMPILE_LOOKIN_SERVER
//
// NSString+Lookin.m
// Lookin
//
// Created by Li Kai on 2019/5/11.
// https://lookin.work
//
#import "NSString+Lookin.h"
@implementation NSString (Lookin)
+ (NSString *)lookin_stringFromDouble:(double)doubleValue decimal:(NSUInteger)decimal {
NSString *formatString = [NSString stringWithFormat:@"%%.%@f", @(decimal)];
NSString *string = [NSString stringWithFormat:formatString, doubleValue];
for (int i = 0; i < decimal; i++) {
if ([[string substringFromIndex:string.length - 1] isEqualToString:@"0"]) {
string = [string substringToIndex:string.length - 1];
}
}
if ([[string substringFromIndex:string.length - 1] isEqualToString:@"."]) {
string = [string substringToIndex:string.length - 1];
}
return string;
}
+ (NSString *)lookin_stringFromInset:(LookinInsets)insets {
return [NSString stringWithFormat:@"{%@, %@, %@, %@}",
[NSString lookin_stringFromDouble:insets.top decimal:2],
[NSString lookin_stringFromDouble:insets.left decimal:2],
[NSString lookin_stringFromDouble:insets.bottom decimal:2],
[NSString lookin_stringFromDouble:insets.right decimal:2]];
}
+ (NSString *)lookin_stringFromSize:(CGSize)size {
return [NSString stringWithFormat:@"{%@, %@}",
[NSString lookin_stringFromDouble:size.width decimal:2],
[NSString lookin_stringFromDouble:size.height decimal:2]];
}
+ (NSString *)lookin_stringFromPoint:(CGPoint)point {
return [NSString stringWithFormat:@"{%@, %@}",
[NSString lookin_stringFromDouble:point.x decimal:2],
[NSString lookin_stringFromDouble:point.y decimal:2]];
}
+ (NSString *)lookin_stringFromRect:(CGRect)rect {
return [NSString stringWithFormat:@"{%@, %@, %@, %@}",
[NSString lookin_stringFromDouble:rect.origin.x decimal:2],
[NSString lookin_stringFromDouble:rect.origin.y decimal:2],
[NSString lookin_stringFromDouble:rect.size.width decimal:2],
[NSString lookin_stringFromDouble:rect.size.height decimal:2]];
}
+ (NSString *)lookin_rgbaStringFromColor:(LookinColor *)color {
if (!color) {
return @"nil";
}
#if TARGET_OS_IPHONE
UIColor *rgbColor = color;
#elif TARGET_OS_MAC
NSColor *rgbColor = [color colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
#endif
CGFloat r, g, b, a;
[rgbColor getRed:&r green:&g blue:&b alpha:&a];
NSString *colorDesc;
if (a >= 1) {
colorDesc = [NSString stringWithFormat:@"(%.0f, %.0f, %.0f)", r * 255, g * 255, b * 255];
} else {
colorDesc = [NSString stringWithFormat:@"(%.0f, %.0f, %.0f, %@)", r * 255, g * 255, b * 255, [NSString lookin_stringFromDouble:a decimal:2]];
}
return colorDesc;
}
- (NSString *)lookin_safeInitWithUTF8String:(const char *)string {
if (NULL != string) {
return [self initWithUTF8String:string];
}
return nil;
}
- (NSInteger)lookin_numbericOSVersion {
if (self.length == 0) {
NSAssert(NO, @"");
return 0;
}
NSArray *versionArr = [self componentsSeparatedByString:@"."];
if (versionArr.count != 3) {
NSAssert(NO, @"");
return 0;
}
NSInteger numbericOSVersion = 0;
NSInteger pos = 0;
while ([versionArr count] > pos && pos < 3) {
numbericOSVersion += ([[versionArr objectAtIndex:pos] integerValue] * pow(10, (4 - pos * 2)));
pos++;
}
return numbericOSVersion;
}
@end
#endif /* SHOULD_COMPILE_LOOKIN_SERVER */