(20170207)开源第三方学习之JSONModel
-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err
{
//check for nil input
//1.为空判断
if (!dict) {
if (err) *err = [JSONModelError errorInputIsNil];
return nil;
} //invalid input, just create empty instance
//2.类型判断
if (![dict isKindOfClass:[NSDictionary class]]) {
if (err) *err = [JSONModelError errorInvalidDataWithMessage:@"Attempt to initialize JSONModel object using initWithDictionary:error: but the dictionary parameter was not an 'NSDictionary'."];
return nil;
} //create a class instance
//3.核心,初始化映射property
self = [self init];
if (!self) { //super init didn't succeed
if (err) *err = [JSONModelError errorModelIsInvalid];
return nil;
} //check incoming data structure
//4.检查映射结构是否能够从dictionary中找到相应的数据
if (![self __doesDictionary:dict matchModelWithKeyMapper:self.__keyMapper error:err]) {
return nil;
} //import the data from a dictionary
//5.进行数据赋值
if (![self __importDictionary:dict withKeyMapper:self.__keyMapper validation:YES error:err]) {
return nil;
} //run any custom model validation
//6.本地数据检查
if (![self validate:err]) {
return nil;
} //model is valid! yay!
return self;
}
unsigned int propertyCount;
objc_property_t *properties = class_copyPropertyList(class, &propertyCount); //loop over the class properties
for (unsigned int i = ; i < propertyCount; i++) { JSONModelClassProperty* p = [[JSONModelClassProperty alloc] init]; //get property name
objc_property_t property = properties[i];
const char *propertyName = property_getName(property);
p.name = @(propertyName); //JMLog(@"property: %@", p.name); //get property attributes
const char *attrs = property_getAttributes(property);
NSString* propertyAttributes = @(attrs);
NSArray* attributeItems = [propertyAttributes componentsSeparatedByString:@",”];
…….
}


NSScanner* scanner = nil;
scanner = [NSScanner scannerWithString: propertyAttributes]; //JMLog(@"attr: %@", [NSString stringWithCString:attrs encoding:NSUTF8StringEncoding]);
[scanner scanUpToString:@"T" intoString: nil];
[scanner scanString:@"T" intoString:nil]; //check if the property is an instance of a class
if ([scanner scanString:@"@\"" intoString: &propertyType]) { [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"<"]
intoString:&propertyType]; //JMLog(@"type: %@", propertyClassName);
p.type = NSClassFromString(propertyType);
p.isMutable = ([propertyType rangeOfString:@"Mutable"].location != NSNotFound);
p.isStandardJSONType = [allowedJSONTypes containsObject:p.type]; //read through the property protocols
while ([scanner scanString:@"<" intoString:NULL]) { NSString* protocolName = nil; [scanner scanUpToString:@">" intoString: &protocolName]; if ([protocolName isEqualToString:@"Optional"]) {
p.isOptional = YES;
} else if([protocolName isEqualToString:@"Index"]) {
p.isIndex = YES;
objc_setAssociatedObject(
self.class,
&kIndexPropertyNameKey,
p.name,
OBJC_ASSOCIATION_RETAIN // This is atomic
);
} else if([protocolName isEqualToString:@"ConvertOnDemand"]) {
p.convertsOnDemand = YES;
} else if([protocolName isEqualToString:@"Ignore"]) {
p = nil;
} else {
p.protocol = protocolName;
} [scanner scanString:@">" intoString:NULL];
} }
//check if the property is a structure
else if ([scanner scanString:@"{" intoString: &propertyType]) {
[scanner scanCharactersFromSet:[NSCharacterSet alphanumericCharacterSet]
intoString:&propertyType]; p.isStandardJSONType = NO;
p.structName = propertyType; }
//the property must be a primitive
else { //the property contains a primitive data type
[scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@","]
intoString:&propertyType]; //get the full name of the primitive type
propertyType = valueTransformer.primitivesNames[propertyType]; if (![allowedPrimitiveTypes containsObject:propertyType]) { //type not allowed - programmer mistaked -> exception
@throw [NSException exceptionWithName:@"JSONModelProperty type not allowed"
reason:[NSString stringWithFormat:@"Property type of %@.%@ is not supported by JSONModel.", self.class, p.name]
userInfo:nil];
} }
然后对符号的字符串进行解析分析,把相应的字符串获取到进行判断处理;对于有增加相应的属性进行操作,如忽略、可为空等,如是block修饰的也直接置空属性,不对它进行转换;代码如下:
NSString *nsPropertyName = @(propertyName);
if([[self class] propertyIsOptional:nsPropertyName]){
p.isOptional = YES;
} if([[self class] propertyIsIgnored:nsPropertyName]){
p = nil;
} //few cases where JSONModel will ignore properties automatically
if ([propertyType isEqualToString:@"Block"]) {
p = nil;
}
+(JSONKeyMapper*)keyMapper
{
return [[JSONKeyMapper alloc] initWithDictionary:@{
@"new_password": @"my_new_password",
}];
}
其实是在JSONModel初始化过程中有对keyMapper进行一个判断处理;判断当前的实体对象中是否有这个方法,如果有且还没有被映射缓存过,则对它进行处理;
id mapper = [[self class] keyMapper];
if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {
objc_setAssociatedObject(
self.class,
&kMapperObjectKey,
mapper,
OBJC_ASSOCIATION_RETAIN // This is atomic
);
}
其中关于&kClassPropertiesKey, &kMapperObjectKey的运用说明,是映射缓存的标识;
//使用AssociateObject进行映射property的缓存,判断是否映射过
if (!objc_getAssociatedObject(self.class, &kClassPropertiesKey)) {
[self __inspectProperties];
} //同样使用AssociateObject进行映射property的缓存
if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {
}
写入标识的操作如下:
objc_setAssociatedObject(
self.class,
&kClassPropertiesKey,
[propertyIndex copy],
OBJC_ASSOCIATION_RETAIN // This is atomic
);
-(NSMutableSet*)__requiredPropertyNames
{
//fetch the associated property names
NSMutableSet* classRequiredPropertyNames = objc_getAssociatedObject(self.class, &kClassRequiredPropertyNamesKey); if (!classRequiredPropertyNames) {
classRequiredPropertyNames = [NSMutableSet set];
[[self __properties__] enumerateObjectsUsingBlock:^(JSONModelClassProperty* p, NSUInteger idx, BOOL *stop) {
if (!p.isOptional) [classRequiredPropertyNames addObject:p.name];
}]; //persist the list
objc_setAssociatedObject(
self.class,
&kClassRequiredPropertyNamesKey,
classRequiredPropertyNames,
OBJC_ASSOCIATION_RETAIN // This is atomic
);
}
return classRequiredPropertyNames;
}
这边要兼容除了dic字典里面的属性还要处理如果有KeyMapper的替换属性;然后进行统一判断;
-(BOOL)__doesDictionary:(NSDictionary*)dict matchModelWithKeyMapper:(JSONKeyMapper*)keyMapper error:(NSError**)err
{
//check if all required properties are present
NSArray* incomingKeysArray = [dict allKeys];
NSMutableSet* requiredProperties = [self __requiredPropertyNames];
NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray]; //transform the key names, if neccessary
if (keyMapper || globalKeyMapper) { NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count];
NSString* transformedName = nil; //loop over the required properties list
for (JSONModelClassProperty* property in [self __properties__]) { transformedName = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name; //chek if exists and if so, add to incoming keys
id value;
@try {
value = [dict valueForKeyPath:transformedName];
}
@catch (NSException *exception) {
value = dict[transformedName];
} if (value) {
[transformedIncomingKeys addObject: property.name];
}
} //overwrite the raw incoming list with the mapped key names
incomingKeys = transformedIncomingKeys;
} //check for missing input keys
if (![requiredProperties isSubsetOfSet:incomingKeys]) { //get a list of the missing properties
[requiredProperties minusSet:incomingKeys]; //not all required properties are in - invalid input
JMLog(@"Incoming data was invalid [%@ initWithDictionary:]. Keys missing: %@", self.class, requiredProperties); if (err) *err = [JSONModelError errorInvalidDataWithMissingKeys:requiredProperties];
return NO;
} //not needed anymore
incomingKeys= nil;
requiredProperties= nil; return YES;
}
-(NSArray*)__properties__
{
//fetch the associated object
NSDictionary* classProperties = objc_getAssociatedObject(self.class, &kClassPropertiesKey);
if (classProperties) return [classProperties allValues]; //if here, the class needs to inspect itself
[self __setup__]; //return the property list
classProperties = objc_getAssociatedObject(self.class, &kClassPropertiesKey);
return [classProperties allValues];
}
然后主要进行属性赋值
-(BOOL)__importDictionary:(NSDictionary*)dict withKeyMapper:(JSONKeyMapper*)keyMapper validation:(BOOL)validation error:(NSError**)err
{
//loop over the incoming keys and set self's properties
//循环遍历映射出来的JSONModelClassProperty结构体
for (JSONModelClassProperty* property in [self __properties__]) { //convert key name ot model keys, if a mapper is provided
//keyMapper映射,获取镇真正的值
NSString* jsonKeyPath = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name;
//JMLog(@"keyPath: %@", jsonKeyPath); //general check for data type compliance
id jsonValue;
@try {
jsonValue = [dict valueForKeyPath: jsonKeyPath];
}
@catch (NSException *exception) {
jsonValue = dict[jsonKeyPath];
} //check for Optional properties
if (isNull(jsonValue)) {
//skip this property, continue with next property
if (property.isOptional || !validation) continue; if (err) {
//null value for required property
NSString* msg = [NSString stringWithFormat:@"Value of required model key %@ is null", property.name];
JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
*err = [dataErr errorByPrependingKeyPathComponent:property.name];
}
return NO;
} Class jsonValueClass = [jsonValue class];
BOOL isValueOfAllowedType = NO; //判断数据输入类型是不是允许的json类型
for (Class allowedType in allowedJSONTypes) {
if ( [jsonValueClass isSubclassOfClass: allowedType] ) {
isValueOfAllowedType = YES;
break;
}
} if (isValueOfAllowedType==NO) {
//type not allowed
JMLog(@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass)); if (err) {
NSString* msg = [NSString stringWithFormat:@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass)];
JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
*err = [dataErr errorByPrependingKeyPathComponent:property.name];
}
return NO;
} //check if there's matching property in the model
if (property) { // check for custom setter, than the model doesn't need to do any guessing
// how to read the property's value from JSON
// 使用对象相应的setter方法进行set
if ([self __customSetValue:jsonValue forProperty:property]) {
//skip to next JSON key
continue;
}; // 0) handle primitives
// 代表基础类型,比如int float等,直接使用kvc赋值
if (property.type == nil && property.structName==nil) { //generic setter
if (jsonValue != [self valueForKey:property.name]) {
[self setValue:jsonValue forKey: property.name];
} //skip directly to the next key
continue;
} // 0.5) handle nils
if (isNull(jsonValue)) {
if ([self valueForKey:property.name] != nil) {
[self setValue:nil forKey: property.name];
}
continue;
} // 1) check if property is itself a JSONModel
// 判断子结构是否是一个JSONModel结构,进行递归遍历,先将子结构遍历完并赋值完成
if ([self __isJSONModelSubClass:property.type]) { //initialize the property's model, store it
JSONModelError* initErr = nil;
id value = [[property.type alloc] initWithDictionary: jsonValue error:&initErr]; if (!value) {
//skip this property, continue with next property
if (property.isOptional || !validation) continue; // Propagate the error, including the property name as the key-path component
if((err != nil) && (initErr != nil))
{
*err = [initErr errorByPrependingKeyPathComponent:property.name];
}
return NO;
}
if (![value isEqual:[self valueForKey:property.name]]) {
[self setValue:value forKey: property.name];
} //for clarity, does the same without continue
continue; } else { // 2) check if there's a protocol to the property
// ) might or not be the case there's a built in transform for it
// 是否包含protocol的字段,该字段主要用来表明array或者dictionary中的对象类型
if (property.protocol) { //JMLog(@"proto: %@", p.protocol);
//循环遍历子内容,将对应的类型赋给相应的array或者dictionary
jsonValue = [self __transform:jsonValue forProperty:property error:err];
if (!jsonValue) {
if ((err != nil) && (*err == nil)) {
NSString* msg = [NSString stringWithFormat:@"Failed to transform value, but no error was set during transformation. (%@)", property];
JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
*err = [dataErr errorByPrependingKeyPathComponent:property.name];
}
return NO;
}
} // 3.1) handle matching standard JSON types
// 判断标准的json类型,比如nsstring等
if (property.isStandardJSONType && [jsonValue isKindOfClass: property.type]) { //mutable properties
if (property.isMutable) {
jsonValue = [jsonValue mutableCopy];
} //set the property value
if (![jsonValue isEqual:[self valueForKey:property.name]]) {
[self setValue:jsonValue forKey: property.name];
}
continue;
} // 3.3) handle values to transform
// 其他处理情况,主要是一些类型转换的情况,比如nsstring转换为nsurl等
if (
(![jsonValue isKindOfClass:property.type] && !isNull(jsonValue))
||
//the property is mutable
property.isMutable
||
//custom struct property
property.structName
) { // searched around the web how to do this better
// but did not find any solution, maybe that's the best idea? (hardly)
// 获取真实的json数据类型
Class sourceClass = [JSONValueTransformer classByResolvingClusterClasses:[jsonValue class]]; //JMLog(@"to type: [%@] from type: [%@] transformer: [%@]", p.type, sourceClass, selectorName); //build a method selector for the property and json object classes
// 通过property类型和json数据类型进行转换的判断
NSString* selectorName = [NSString stringWithFormat:@"%@From%@:",
(property.structName? property.structName : property.type), //target name
sourceClass]; //source name
SEL selector = NSSelectorFromString(selectorName); //check for custom transformer
//是否有本地转换的方法
BOOL foundCustomTransformer = NO;
if ([valueTransformer respondsToSelector:selector]) {
foundCustomTransformer = YES;
} else {
//try for hidden custom transformer
selectorName = [NSString stringWithFormat:@"__%@",selectorName];
selector = NSSelectorFromString(selectorName);
if ([valueTransformer respondsToSelector:selector]) {
foundCustomTransformer = YES;
}
} //check if there's a transformer with that name
if (foundCustomTransformer) { //it's OK, believe me...
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//transform the value
// 通过 JSONValueTransformer 进行类型转换
jsonValue = [valueTransformer performSelector:selector withObject:jsonValue];
#pragma clang diagnostic pop if (![jsonValue isEqual:[self valueForKey:property.name]]) {
[self setValue:jsonValue forKey: property.name];
} } else { // it's not a JSON data type, and there's no transformer for it
// if property type is not supported - that's a programmer mistake -> exception
@throw [NSException exceptionWithName:@"Type not allowed"
reason:[NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name]
userInfo:nil];
return NO;
} } else {
// 3.4) handle "all other" cases (if any)
if (![jsonValue isEqual:[self valueForKey:property.name]]) {
[self setValue:jsonValue forKey: property.name];
}
}
}
}
} return YES;
}
其中获取到值对应的类型是否在支持的转化类型中
allowedJSONTypes = @[
[NSString class], [NSNumber class], [NSDecimalNumber class], [NSArray class], [NSDictionary class], [NSNull class], //immutable JSON classes
[NSMutableString class], [NSMutableArray class], [NSMutableDictionary class] //mutable JSON classes
]; allowedPrimitiveTypes = @[
@"BOOL", @"float", @"int", @"long", @"double", @"short",
//and some famous aliases
@"NSInteger", @"NSUInteger",
@"Block"
];
然后上面的代码用于下面进行判断
Class jsonValueClass = [jsonValue class];
BOOL isValueOfAllowedType = NO; for (Class allowedType in allowedJSONTypes) {
if ( [jsonValueClass isSubclassOfClass: allowedType] ) {
isValueOfAllowedType = YES;
break;
}
}
2.6 定义空的协议用于区分一些属性标识
@protocol Ignore
@end /**
* Protocol for defining optional properties in a JSON Model class. Use like below to define
* model properties that are not required to have values in the JSON input:
*
* @property (strong, nonatomic) NSString<Optional>* propertyName;
*
*/
@protocol Optional
@end /**
* Protocol for defining index properties in a JSON Model class. Use like below to define
* model properties that are considered the Model's identifier (id).
*
* @property (strong, nonatomic) NSString<Index>* propertyName;
*
*/
@protocol Index
@end //使所有对象可选兼容,避免编译器警告
@interface NSObject(JSONModelPropertyCompatibility)<Optional, Index, Ignore>
@end
特别是Optional为可空的标识例如我们给一个属性设置可空时 @property (nonatomic, copy) NSString<Optional> *current_status;,然后在上面获取属性的字符串中关于是否存在这个标识字符串,做一些属性的配置;它是被包含在<>里面;
while ([scanner scanString:@"<" intoString:NULL]) {
                    NSString* protocolName = nil;
                    [scanner scanUpToString:@">" intoString: &protocolName];
                    if ([protocolName isEqualToString:@"Optional"]) {
                        p.isOptional = YES;
                    } else if([protocolName isEqualToString:@"Index"]) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
                        p.isIndex = YES;
#pragma GCC diagnostic pop
                        objc_setAssociatedObject(
                                                 self.class,
                                                 &kIndexPropertyNameKey,
                                                 p.name,
                                                 OBJC_ASSOCIATION_RETAIN // This is atomic
                                                 );
                    } else if([protocolName isEqualToString:@"Ignore"]) {
                        p = nil;
                    } else {
                        p.protocol = protocolName;
                    }
                    [scanner scanString:@">" intoString:NULL];
                }
            }
3:关于属性类型的获取实例
定义一个类:
@interface MPAllModel : JSONModel @property(nonatomic,copy)NSString *name;
@property(nonatomic,strong)NSString *userName;
@property(nonatomic)int age;
@property(nonatomic)float price;
@property(nonatomic,strong)NSNumber *isShow;
@property(nonatomic,assign)BOOL isError;
@property(nonatomic,strong)NSArray *itemArray;
@property(nonatomic,strong)NSArray<Optional> *dataArray;
@end
然后利用运行时的代码,获得到这个类对应属性的字符串内容:
unsigned int outCount;
int i;
objc_property_t *property = class_copyPropertyList([MPAllModel class], &outCount);
for (i = outCount -; i >= ; i--) {
NSString *getPropertyName = [NSString stringWithCString:property_getName(property[i]) encoding:NSUTF8StringEncoding];
NSLog(@"getPropertyName: %@",getPropertyName);
NSString *getPropertyNameString = [NSString stringWithCString:property_getAttributes(property[i]) encoding:NSUTF8StringEncoding];
NSLog(@"getPropertyNameString: %@",getPropertyNameString);
}
得到下面对应的类型:
getPropertyName: dataArray
getPropertyNameString: T@"NSArray<Optional>",&,N,V_dataArray getPropertyName: itemArray
getPropertyNameString: T@"NSArray",&,N,V_itemArray getPropertyName: isError
getPropertyNameString: TB,N,V_isError getPropertyName: isShow
getPropertyNameString: T@"NSNumber",&,N,V_isShow getPropertyName: price
getPropertyNameString: Tf,N,V_price getPropertyName: age
getPropertyNameString: Ti,N,V_age getPropertyName: userName
getPropertyNameString: T@"NSString",&,N,V_userName getPropertyName: name
getPropertyNameString: T@"NSString",C,N,V_name
最近有个妹子弄的一个关于扩大眼界跟内含的订阅号,每天都会更新一些深度内容,在这里如果你感兴趣也可以关注一下(嘿对美女跟知识感兴趣),当然可以关注后输入:github 会有我的微信号,如果有问题你也可以在那找到我;当然不感兴趣无视此信息;

(20170207)开源第三方学习之JSONModel的更多相关文章
- (20160604)开源第三方学习之CocoaLumberjack
		
CocoaLumberjack是一个很好用的日志打印工具,它可以帮助我们把工程中的日志信息打印到终端或者输出到文件中. 地址:https://github.com/CocoaLumberjack/Co ...
 - (20160602)开源第三方学习之SDWebImage
		
这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下载.同一个URL下载次数控制和优化等特征. 地址:https://github.com/rs/SDWebIm ...
 - (20160601)开源第三方学习之SVProgressHUD
		
SVProgressHUD相信在很多项目中都有运用,运用于弹出窗提示效果: 地址:https://github.com/SVProgressHUD/SVProgressHUD 一:插件的运用 1.1 ...
 - 开源深度学习架构Caffe
		
Caffe 全称为 Convolutional Architecture for Fast Feature Embedding,是一个被广泛使用的开源深度学习框架(在 TensorFlow 出现之前一 ...
 - GitHub 上 57 款最流行的开源深度学习项目
		
转载:https://www.oschina.net/news/79500/57-most-popular-deep-learning-project-at-github GitHub 上 57 款最 ...
 - 转:从开源项目学习 C 语言基本的编码规则
		
从开源项目学习 C 语言基本的编码规则 每个项目都有自己的风格指南:一组有关怎样为那个项目编码约定.一些经理选择基本的编码规则,另一些经理则更偏好非常高级的规则,对许多项目而言则没有特定的编码规则,项 ...
 - 推荐GitHub上10 个开源深度学习框架
		
推荐GitHub上10 个开源深度学习框架 日前,Google 开源了 TensorFlow(GitHub),此举在深度学习领域影响巨大,因为 Google 在人工智能领域的研发成绩斐然,有着雄厚 ...
 - Computational Network Toolkit (CNTK) 是微软出品的开源深度学习工具包
		
Computational Network Toolkit (CNTK) 是微软出品的开源深度学习工具包 用 CNTK 搞深度学习 (一) 入门 Computational Network Toolk ...
 - 谷歌重磅开源强化学习框架Dopamine吊打OpenAI
		
谷歌重磅开源强化学习框架Dopamine吊打OpenAI 近日OpenAI在Dota 2上的表现,让强化学习又火了一把,但是 OpenAI 的强化学习训练环境 OpenAI Gym 却屡遭抱怨,比如不 ...
 
随机推荐
- P1120 小木棍 [数据加强版]   回溯法 终极剪枝
			
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度 ...
 - js(javaScript)的各种事件触发,以常见为主eg:onclick
			
js的各种事件触发,以常见为主eg:onclick1.onclick,点击后触发事件 (1)<h1 onclick="this.innerHTML='谢谢!'">请点击 ...
 - 1e9个兵临城下
			
https://ac.nowcoder.com/acm/contest/321#question 代码写得蛮丑的..真的很丑 像是高中教的veen图,并涉及到容斥原理. #include<cst ...
 - PHP环境配置错误处理
			
[Linux apt-get 更换源] 1.问题描述:按照网上的教程编辑源列表文件后发现apt-get update 出现各种错误,导致更新失败 sudo vim /etc/apt/sources.l ...
 - URAL 1099 Work Scheduling (一般图最大匹配) 模板题【带花树】
			
<题目链接> <转载于 >>> > 题目大意: 给出n个士兵,再给出多组士兵之间两两可以匹配的关系.已知某个士兵最多只能与一个士兵匹配.求最多能够有多少对匹 ...
 - HDU 1045 Fire Net 【二分图匹配】
			
<题目链接> 题目大意: 这题意思是给出一张图,图中'X'表示wall,'.'表示空地,可以放置炮台,同一条直线上只能有一个炮台,除非有'X'隔开,问在给出的图中最多能放置多少个炮台. 解 ...
 - POJ 2631 Roads in the North (模板题)(树的直径)
			
<题目链接> 题目大意:求一颗带权树上任意两点的最远路径长度. 解题分析: 裸的树的直径,可由树形DP和DFS.BFS求解,下面介绍的是BFS解法. 在树上跑两遍BFS即可,第一遍BFS以 ...
 - 关闭VS2015的WPF UI调试工具
			
VS菜单: 工具 > 选项 > 调试 > 常规 > 启用Xaml 的UI调试工具.把勾勾去掉.
 - 前缀和的应用 CodeForces - 932B Recursive Queries
			
题目链接: https://vjudge.net/problem/1377985/origin 题目大意就是要你把一个数字拆开,然后相乘. 要求得数要小于9,否则递归下去. 这里用到一个递归函数: i ...
 - 嵌入式单片机STM32应用技术(课本)
			
目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...