0%

定位问题

using background location services must provide a reason that clarifies the purpose of the use, using mechanisms described in the Human Interface Guidelines

这个原因主要是向用于请求定位权限时,要说明原因.

解决方法
在info.plist文件中设置下面两个字段

占位符问题

we found that your app and/or its metadata does not appear to include final content, which is not in compliance with the App Store Review Guidelines

可能原因一:这个原因主要是图片的placeholder,当从服务器没有请求到图片时,显示的placeholder图片被苹果认为是半成品的APP
可能原因二:在上架项目的时候对于APP的介绍描述不清楚,能吹则吹,多写点,又死不了人.

解决方法
在服务器弄好完整的图片,让APP能请求到.多些应用的描述.


以上方法仅限于理论,因为需要上架的项目没有源码.

–EOF–

报错信息

ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later (@rpath/Alamofire.framework/Alamofire) for architecture x86_64

其实从名字大概也能猜出来,某个库支持的最低部署环境是8.0.

修改方法

我这应该修改成8.0

本文参考xyxjn的专栏

–EOF–

步骤

  1. 获取JSON文件路径
  2. 根据路径创建NSData对象
  3. 根据NSData对象对JSON进行序列化,得到一个数组
  4. 遍历数组,提取出视图名,标题,图片名,根据这三项创建视图,并用UINavigationViewController包裹起来,将navi添加到tabBarViewController中.

MainVCSettings.json文件

[
 {
    "vcName": "HomeTableViewController",
    "title": "首页",
    "imageName": "tabbar_home"
 },
 {
     "vcName": "MessageTableViewController",
     "title": "消息",
     "imageName": "tabbar_message_center"
 },
 {
 "vcName": "NullViewController",
 "title": "",
 "imageName": ""
 },
 {
     "vcName": "DiscoverTableViewController",
     "title": "广场",
     "imageName": "tabbar_discover"
 },
 {
     "vcName": "ProfileTableViewController",
     "title": "我",
     "imageName": "tabbar_profile"
 }
 ]

具体实现代码

//
// MainViewController.swift
// weibo
//
// Created by Adrift on 16/6/5.
// Copyright © 2016年 Adrift. All rights reserved.
//

import UIKit

class MainViewController: UITabBarController {

    //MARK: - 生命周期
    override func viewDidLoad() {
        super.viewDidLoad()
        //设置当前控制器对应的tabBar的颜色,iOS7之前如果设置了tintClor只有文字会变,而图片不会变
        tabBar.tintColor = UIColor.orangeColor()
        addChildViewControllers()
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)
        tabBar.addSubview(composeBtn)
        //计算宽度
        let width = UIScreen.mainScreen().bounds.width / CGFloat(viewControllers!.count)
        //创建 frame
        let rect = CGRect(x: 0, y: 0, width: width, height: tabBar.bounds.height)
        //设置 frame 跟 偏移量
        composeBtn.frame = CGRectOffset(rect, width * 2, 0)
        
    }
    
    //MARK: - 方法
    /**
     添加所有子控制器
     */
    func addChildViewControllers() {
        //获取json文件路径
        let path = NSBundle.mainBundle().pathForResource("MainVCSettings", ofType: "json")
        //通过文件路径创建NSData
        if let tempPath = path {
            let jsonData = NSData(contentsOfFile: tempPath)
            do {
                //序列化
                let dictArr = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers) as! [[String: String]]
                //遍历数组,并创建视图控制器
                for dict in dictArr {
                    addChildViewController(dict["vcName"]!, title: dict["title"]!, imageName: dict["imageName"]!)
                }
            }catch{
                print("crash")
                //并添加到TabBarViewController
                addChildViewController("HomeTableViewController", title: "首页", imageName: "tabbar_home")
                addChildViewController("MessageTableViewController", title: "消息", imageName: "tabbar_message_center")
                addChildViewController("NullViewController", title: "", imageName: "")
                addChildViewController("DiscoverTableViewController", title: "发现", imageName: "tabbar_discover")
                addChildViewController("ProfileTableViewController", title: "我的", imageName: "tabbar_profile")
            }
        }
    }
    
    /**
     将navigationViewController 添加到 TabBarViewController
     
     - parameter childController: 子控制图
     - parameter title: 标题
     - parameter imageName: 非高亮图片名称
     */
    private func addChildViewController(childControllerName: String, title: String, imageName: String) {
        //获取命名空间
        let speaceName = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
        
        //通过字符串转换为类
        let cls:AnyClass? = NSClassFromString(speaceName + "." + childControllerName)
        
        //通过类创建对象
        let vcCls = cls as! UIViewController.Type
        let vc = vcCls.init()

// 设置首页
        vc.tabBarItem.image = UIImage(named: imageName)
        vc.tabBarItem.selectedImage = UIImage(named: imageName + "_highlighted")
        vc.title = title
        //2.给首页包装一个导航器
        let navi = UINavigationController()
        navi.addChildViewController(vc)
        //3.将导航控制器添加到当前控制器
        addChildViewController(navi)
    }
    
    func composeBtnClick() {
        print("被点击...")
    }
    
    //MARK: - 懒加载
    private lazy var composeBtn:UIButton = {
        
        let button = UIButton()
        
        //设置button图片
        button.setImage(UIImage(named: "tabbar_compose_icon_add"), forState: UIControlState.Normal)
        button.setImage(UIImage(named: "tabbar_compose_icon_add_highlighted"), forState: UIControlState.Highlighted)
        
        //设置button背景图片
        button.setBackgroundImage(UIImage(named: "tabbar_compose_button"), forState: UIControlState.Normal)
        button.setBackgroundImage(UIImage(named: "tabbar_compose_button_highlighted"), forState: UIControlState.Highlighted)
        
        //添加监听事件
        button.addTarget(self, action: #selector(MainViewController.composeBtnClick), forControlEvents: UIControlEvents.TouchUpInside)
        
        return button
    }()
}

–EOF–

自从安装Ghost博客之后,邮件服务都是被弃用的…闲的无聊,百度了一下…

mail: {
    transport: 'SMTP',
    host: 'smtp.qq.com',
    fromaddress: 'vip@qq.com',
    options: {
        port: 465,
        service: 'QQ',
        auth: {
            user: 'vip@qq.com',
            pass: 'abcdefg123456789'
        }
    }
}

设置之后可以发QQ邮件,如果是其他邮箱,修改一下host就可以了.

本文参考:Ghost博客系统数据库自动邮件备份

–EOF–

迷你码农遇到的个性化问题.遇到这个问题还得上网查,说明对Git不了解.有时间看看廖雪峰的Git教程.

报错信息

报错信息

解决方法

  1. 在Github Desktop客户端右击项目,然后Open in Terminal
  2. 输入命令:ls -al,会看到.git文件夹
  3. 输入命令:cd .git,打开.git文件夹
  4. 输入命令:ls -al,会看到config文件
  5. 输入命令:vim config,打开config文件
  6. 按键盘键,将光标移动到[remote "origin"]这行,按键盘i键进入插入模式.
  7. delete键删除包括本行在内的三行
  8. 删除完之后,按Esc键,退出编辑模式.然后英文状态下输入shift+:,输入wq,保存退出.
  9. Github Desktop完全退出重新打开,现在就能Sync了.

参考链接:Solved: ERROR: Repository not found

–EOF–

同学前几天面试面到了这个题,毕竟闷了半天才闷出来.记录一下省的忘了…

NSString+Category.h文件

#import <Foundation/Foundation.h>

@interface NSString (Category)

/**
 * 根据分隔符,分隔字符串
 *
 * @param symbol 分隔符
 *
 * @return 由被分隔完的字串组成的数组
 */
- (NSArray *)splitStringWithSymbol:(NSString *)symbol;

@end

NSString+Category.m文件

#import "NSString+Category.h"

@implementation NSString (Category)

- (NSArray *)splitStringWithSymbol:(NSString *)symbol {
    
    if (!self || [self isEqualToString:@""] || !symbol || [self isEqualToString:@""]) {
        NSException *e = [NSException exceptionWithName:@"NullPointerException" reason:@"self and symbol can't be nil or @\"\"" userInfo:nil];
        @throw e;
    }
    
    NSMutableArray *mutableArr = [NSMutableArray new];
    NSInteger length = symbol.length;
    NSString *tempStr = nil;
    
    for (int startIndex = 0, endIndex = 0; endIndex <= self.length - length; endIndex++) {
        
        tempStr = [self substringWithRange:NSMakeRange(endIndex, length)];
        if ([tempStr isEqualToString:symbol]) {
            NSString *splitedString = [self substringWithRange:NSMakeRange(startIndex, endIndex - startIndex)];
            if (splitedString && ![splitedString isEqualToString:@""]) {
                [mutableArr addObject:splitedString];
            }
            startIndex = endIndex + (int)length;
        } else if (endIndex == self.length - length){
            NSString *splitedString = [self substringWithRange:NSMakeRange(startIndex, endIndex - startIndex + length)];
            if (splitedString && ![splitedString isEqualToString:@""]) {
                [mutableArr addObject:splitedString];
            }
        }
        
    }
    
    return [mutableArr copy];
}
@end

以上代码有个问题,当字符串是,asdf,,123,分隔字符是,,分隔结果是(asdf,123),而不是(asdf,(前面一个是数组的逗号),123).
试了一下官方的componentsSeparatedByString方法,相同的字符串跟分隔符,输出结果是("",asdf,"",123),连是否是@""都没判断.Java当中实验的结果跟OC结果相同.官方方法都这样,我想我是想多了.

–EOF–

封装的几种方法

  1. 分类:UITextField/UISearchBar
  2. 自定义控件
  3. 工具类

从上到下优先度依次降低.

用哪种方式封装

通过分类,如果通过分类[UITextField searchBar]方法名跟类名明显对不上号;[UISearchBar searchBar]返回结果是一个UITextField,跟类名也对不上.所以我们需要自定控件,自定义控件就需要继承UITextField.

代码

== CTSearchBar.h 文件==

#import <UIKit/UIKit.h>

@interface CTSearchBar : UITextField
+ (instancetype)searchBar;
@end

CTSearchBar.m

#import "CTSearchBar.h"

@implementation CTSearchBar

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.font = [UIFont systemFontOfSize:15];
        self.placeholder = @"请输入搜索内容";
        self.clearsOnBeginEditing = YES;
        self.clearButtonMode = UITextFieldViewModeAlways;
        
        UIImage *image = [UIImage imageNamed:@"searchbar_textfield_search_icon"];
        UIImageView *searchIcon = [[UIImageView alloc] initWithImage:image];
        searchIcon.width = 30;
        searchIcon.height = 30;
        searchIcon.contentMode = UIViewContentModeCenter;
        
        self.leftView = searchIcon;
        self.leftViewMode = UITextFieldViewModeAlways;
    }
    return self;
}

+ (instancetype)searchBar {
    return [[self alloc] init];
}
@end

调用方式

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITextField *searchBar = [CTSearchBar searchBar];
    searchBar.width = 500;
    searchBar.height = 35;
    self.navigationItem.titleView = searchBar;
}

上面代码中searchBar.width = 500;这种方式是因为我给UIView做了一个分类,所以可以直接赋值.详见:通过Category让UIView更方便的布局

以上仅提供简单思路,还可以封装更加复杂的搜索框,像新浪微博的.

–EOF–

原因:

  1. 项目中多次用到自定义UIBarButtonItem,所以需要抽取出来
  2. 代码该干什么就干什么,因为这段代码是自定义。UIBarButtonItem,所以应该由UIBarButtonItem做。所以创建一个分类。
  3. 命名习惯,代码规范。要用[UIBarButtonItem itemWith…]这种形式。

自定义UIBarButtonItem

UIBarButtonItem+Category.h文件

#import <UIKit/UIKit.h>

@interface UIBarButtonItem (Category)
+ (NSArray *)itemWithTarget:(id)target action:(SEL)action image:(NSString *)image lighlightImage:(NSString *)lighlightImage;
@end

UIBarButtonItem+Category.m文件

#import "UIBarButtonItem+Category.h"

@implementation UIBarButtonItem (Category)

/**
 * 自定义一个UIBarButtomItem
 *
 * @param target 点击之后调用哪个对象
 * @param action 点击之后调用对象里面的哪个方法
 * @param image 普通状态下图片
 * @param lighlightImage 高亮状态下图片
 *
 * @return 创建完的一个UIBarButtomItem数组
 */
+ (NSArray *)itemWithTarget:(id)target action:(SEL)action image:(NSString *)image lighlightImage:(NSString *)lighlightImage {
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:lighlightImage] forState:UIControlStateHighlighted];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    button.size = button.currentImage.size;
    
    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc]initWithCustomView:button];
    UIBarButtonItem *speaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    speaceItem.width = -5;
    
    return @[speaceItem,buttonItem];
}

@end

调用

在ViewController调用或者在自定义的UINavigationController的push方法里面调用。

//ViewController调用
self.navigationItem.leftBarButtonItems = [UIBarButtonItem itemWithTarget:self action:@selector(back) image:@"back_icon_red" lighlightImage:@"back_icon_red"];
//自定义UINavigationController的push方法调用
viewController.navigationItem.leftBarButtonItems = [UIBarButtonItem itemWithTarget:self action:@selector(back) image:@"back_icon_red" lighlightImage:@"back_icon_red"];

注意:action方法写在ViewController或自定义UINavigationController里面。

当然还可以在分类里做其他自定义的样式。

–EOF–

方法一

通过工厂方法,然后在需要左上角显示图标的ViewController的viewDidLoad方法调用。代码如下:

Factory.h文件

#import <Foundation/Foundation.h>

@interface Factory : NSObject
+ (void)addBackButton:(UIViewController *)viewController;
@end
1
==Factory.m文件==
#import "Factory.h" @implementation Factory + (void)addBackButton:(UIViewController *)viewController{ UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setImage:[UIImage imageNamed:@"community_highlight"] forState:UIControlStateNormal]; [button setImage:[UIImage imageNamed:@"community_highlight"] forState:UIControlStateHighlighted]; CGRect frame = button.frame; frame.size = button.currentImage.size; button.frame = frame; UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc]initWithCustomView:button]; UIBarButtonItem *speaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; speaceItem.width = -5; viewController.navigationItem.leftBarButtonItems = @[speaceItem,buttonItem]; } @end
1
2
3
4
### 方法二
这种方法是通过实现UINavigationController的pushViewController方法,拦截所有push进来的viewController,然后对其进行设置。代码如下:

==BaseNavigationController.h文件==
#import <UIKit/UIKit.h> @interface BaseNavigationController : UINavigationController @end
1
==BaseNavigationController.m文件==
#import "BaseNavigationController.h" @interface BaseNavigationController () @end @implementation BaseNavigationController - (void)addBackButton:(UIViewController *)viewController{ if (self.viewControllers.count > 0) { viewController.hidesBottomBarWhenPushed = YES; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setImage:[UIImage imageNamed:@"back_icon_red"] forState:UIControlStateNormal]; [button setImage:[UIImage imageNamed:@"back_icon_red"] forState:UIControlStateHighlighted]; [button addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside]; button.size = button.currentImage.size; UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc]initWithCustomView:button]; UIBarButtonItem *speaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; speaceItem.width = -5; viewController.navigationItem.leftBarButtonItems = @[speaceItem,buttonItem]; } } - (void)back{ [self popViewControllerAnimated:YES]; } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ NSLog(@"push"); [self addBackButton:viewController]; [super pushViewController:viewController animated:animated]; } #pragma -mark 生命周期 - (void)viewDidLoad { [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end ``` > 注意: 1. 用方法一如果某个viewController需要单独设置navigationItem的图标,则在ViewController的viewDidLoad方法里设置即可。 2. 用了方法二如果在push之前调用设置view样式有关的方法,则先调用viewDidLoad方法,然后调用push方法。这时如果在viewDidLoad方法里设置navigationItem的图标将跟push方法拦截viewController设置的效果一样。 > 所谓的拦截,大部分都是通过自定义类,然后重写自带方法实现的。 **--EOF--**

之前我们给一个控件设置宽高或者位置的时候会用下面代码:

    UIView *view = [UIView new];
    CGRect frame = view.frame;
    frame.size.width = 100;
    view.frame = frame;

上面方式很麻烦,不解释。下面是对UIView的分类,方便了对控件的布局:
UIView+Category.h文件

#import <UIKit/UIKit.h>

@interface UIView (Extension)
@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
@property (nonatomic,assign) CGSize size;
@property (nonatomic,assign) CGPoint origin;
//- (void)setX:(CGFloat)x;
//- (CGFloat)x;
//- (void)setY:(CGFloat)y;
//- (CGFloat)y;
//- (void)setWidth:(CGFloat)width;
//- (CGFloat)width;
//- (void)setHeight:(CGFloat)height;
//- (CGFloat)height;
//- (void)setOrigin:(CGPoint)origin;
//- (CGPoint)origin;
//- (void)setSize:(CGSize)size;
//- (CGSize)size;
@end

UIView+Category.m文件

#import "UIView+Category.h"

@implementation UIView (Extension)
- (void)setX:(CGFloat)x {
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}

- (CGFloat)x {
    return self.frame.origin.x;
}

- (void)setY:(CGFloat)y {
    CGRect frame = self.frame;
    frame.origin.y = y;
    self.frame = frame;
    self.frame = frame;
}

- (CGFloat)y {
    return self.frame.origin.y;
}

- (void)setWidth:(CGFloat)width {
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}

- (CGFloat)width {
    return self.frame.size.width;
}

- (void)setHeight:(CGFloat)height {
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}

- (CGFloat)height {
    return self.frame.size.height;
}

- (void)setOrigin:(CGPoint)origin {
    CGRect frame = self.frame;
    frame.origin = origin;
    self.frame = frame;
}

- (CGPoint)origin {
    return self.frame.origin;
}

- (void)setSize:(CGSize)size {
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}

- (CGSize)size {
    return self.frame.size;
}
@end

现在就可以通过下面方式对UIView进行布局了:

    UIView *view = [UIView new];
    view.width = 100;
    view.height = 100;
    view.x = 100;
    view.y = 100;
    //或者
    view.origin = CGPointMake(100, 100);
    view.size = CGSizeMake(100, 100);

最后你可能有疑问,category中不是不能定义属性么?即使可以定义属性,不应该用runtime来实现setter跟getter方法么?

  1. category中的属性不能自动生成实例变量(类似:_xxx),所以我们有时会看到通过runtime的方式将变量绑定到实例上。
  2. 上面例子,定义属性为了生成setter跟getter方法。没有用到任何有关self.xself.yself.width或者_x_y这些自定义属性,都是通过UIView自带属性frame(self.frame)来实现给UIView设置布局,所以不需要用runtime。所以本例子不定义属性也可以,把属性注释掉,然后将下面方法取消注释,一样能用。

–EOF–