iOS项目笔记

1.根据服务端返回的json 字符串中的 \n 让label的文字换行

UIFont *ltextFont = [UIFont systemFontOfSize:14];
    NSString *str = @"活动时间:2016年12月23日--2017年1月6日\n作品要求:设计稿,形式体裁不限,作品尺寸为A4纸。将作品以图文的形式参与话题,文字注明城市与名字,自建话题无效。\n评选方式:平台用户以点赞方式投票\n活动奖励:前三名的作品除平台金币奖励外,还会获得超牛逼涂鸦书籍。";
    CGSize size = [str sizeWithFont: ltextFont constrainedToSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), MAXFLOAT)lineBreakMode:NSLineBreakByWordWrapping];
    
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0,200,size.width,size.height)];
    label.numberOfLines = 0; // 最关键的一句
    label.text = str;
    label.font = ltextFont;
    [self.view addSubview:label];

2.显示时间(几分钟前,几小时前,几天前)

+ (NSString *)compareCurrentTime:(NSString *)str {
    NSString *timeStr = @"2016-02-22 19:27:38";
    // 将时间字符串转换为NSDate
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyy-MM-dd HH:mm:ss"];
    NSDate *timeDate = [dateFormatter dateFromString:timeStr];
    
    // 获取当前时间
    NSDate *currentDate = [NSDate date];
    // 获取当前时间距离timeStr的时间差
    NSTimeInterval timeInterVal = [currentDate timeIntervalSinceDate:timeDate];
    
    long temp = 0;
    NSString *resultStr;
    
    if (timeInterVal / 60 < 1) {
        resultStr = @"刚刚";
        
    } else if ((temp = timeInterVal / 60) < 60) {
        resultStr = [NSString stringWithFormat:@"%ld分钟前", temp];
    } else if ((temp = temp / 60) < 24) {
        resultStr = [NSString stringWithFormat:@"%ld小时前", temp];
    } else if ((temp = temp / 24) < 30) {
        resultStr = [NSString stringWithFormat:@"%ld天前", temp];
    } else if ((temp = temp / 30) < 12) {
        resultStr = [NSString stringWithFormat:@"%ld月前", temp];
        
    } else {
        temp = temp / 12;
        resultStr = [NSString stringWithFormat:@"%ld年前", temp];
    }
    
    return resultStr;
}

3.中文斜体

经查阅资料-- iOS中不支持中文字体倾斜,只有设置倾斜角度

// 1.设置反射。倾斜15度
CGAffineTransform matrix =  CGAffineTransformMake(1, 0, tanf(15 * (CGFloat)M_PI / 180), 1, 0, 0);
// 2.取得系统字符并设置反射
UIFontDescriptor *desc = [ UIFontDescriptor fontDescriptorWithName:[UIFont systemFontOfSize :18].fontName matrix:matrix];
// 3.获取字体
UIFont *font = [UIFont fontWithDescriptor:desc size:18];
    self.rankingBtn.titleLabel.font = font;

 // 4.设置文字的字体,可以画出来
[string. text drawInRect :dr withFont :font lineBreakMode : NSLineBreakByTruncatingTail ];
// 也可以直接设置,比如
// [self.rankingBtn setTitle:viewModel.item.ranking forState:UIControlStateNormal];
   
    通过以上方法--绘制出斜体字。

4.iOS四种切除圆角的方法

  • 通过shapeLayer设置
    通过bezizerpath设置一个路径,加到目标视图的layer上。代码如下
// 创建一个view
  UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
  [self.view addSubview:showView];
  showView.backgroundColor = [UIColor whiteColor];
  showView.alpha = 0.5;

   // 贝塞尔曲线(创建一个圆)
    UIBezierPath *path = [UIBezierPath     bezierPathWithArcCenter:CGPointMake(100 / 2.f, 100 / 2.f)
                                                        radius:100 / 2.f
                                                       startAngle:0 
                                                       endAngle:M_PI * 2
                                                      clockwise:YES];

      CAShapeLayer *layer = [CAShapeLayer layer];
      layer.frame = showView.bounds;
      layer.path = path.CGPath;
      [showView.layer addSublayer:layer];
  • 通过view的layer设置
- (UIImageView  *)avatarImage { 

     if (!_avatarImage) { 

        _avatarImage = [[UIImageView alloc] initWithFrame:CGRectMake(20,10, avatarDiameter, avatarDiameter)];
        _avatarImage.backgroundColor = [UIColor grayColor];
        _avatarImage.contentMode = UIViewContentModeScaleAspectFit;
        _avatarImage.layer.cornerRadius = avatarDiameter/2.0;
        _avatarImage.layer.masksToBounds = YES;
        [_avatarImage setImage:[UIImage imageNamed:@"test.jpg"]];
      }
    return _avatarImage;
}
  • 通过BezierPath设置
- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {

    }
    return self;
}
// 自定义一个类继承自UIView,使用drawRect画圆
- (void)drawRect:(CGRect)rect { 
     // Drawing code 
    CGRect bounds = self.bounds;
    [[UIColor whiteColor] set];
    UIRectFill(bounds);

    [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:CGRectGetWidth(bounds)/2.0] addClip];
    [self.image drawInRect:bounds];
}
  • 通过贴图的方式设置
    贴图的方式是利用一张中间为透明圆形的图片来进行遮盖,注意:要让圆形图片所在的cell的背景颜色与贴图的背景颜色相同, 代码如下:
    // 头像控件
    self.headerView = [UIButton buttonWithType:UIButtonTypeCustom];
    self.headerView.backgroundColor = kColorGlobalCell;
    self.headerView.hidden = NO;
    self.headerView.tag = NSIntegerMax;
    self.headerView.clipsToBounds = YES;
    [self.contentView addSubview:self.headerView];
    
    // 镂空的圆形图片盖在头像上面,目的是让头像显示为圆形, 
    self.cornerImageView = [[UIImageView alloc] init];
    self.cornerImageView.center = self.headerView.center;
    self.cornerImageView.image = [UIImage imageNamed:@"corner_circle"];
    self.cornerImageView.tag = NSIntegerMax;
    [self.contentView addSubview:self.cornerImageView];
self.headerView.frame = self.viewModel.headerFrame;
    self.cornerImageView.frame = CGRectMake(0, 0, CGRectGetWidth(self.viewModel.headerFrame)+5, CGRectGetHeight(self.viewModel.headerFrame)+5);
    self.cornerImageView.center = self.headerView.center;

利用透明圆形的图片来进行遮盖,会引起blending,但性能仍然很高的

Blending:
在iOS的图形处理中,blending主要指的是混合像素颜色的计算。最直观的例子就是,我们把两个图层叠加在一起,如果第一个图层的透明的,则最终像素的颜色计算需要将第二个图层也考虑进来。这一过程即为Blending。
会导致blending的原因:
layer(UIView)的Alpha < 1
UIImgaeView的image含有Alpha channel(即使UIImageView的alpha是1,但只要image含透明通道,则仍会导致Blending)

为什么Blending会导致性能的损失?
原因是很直观的,如果一个图层是不透明的,则系统直接显示该图层的颜色即可。而如果图层是透明的,则会引入更多的计算,因为需要把下面的图层也包括进来,进行混合后颜色的计算。

下面是一个镂空的圆形图片


corner_circle@2x.png

5 将NSInteger类型的秒,转换为00:00:00格式

- (NSString *)coverTime:(NSInteger)secondCount {
    
    // 时
    NSString *tmphh = [NSString stringWithFormat:@"%ld",secondCount / 3600];
    NSLog(@"tmphh--%@", tmphh);
    if ([tmphh length] == 1){
        tmphh = [NSString stringWithFormat:@"0%@",tmphh];
    }
    
    // 分
    NSString *tmpmm = [NSString stringWithFormat:@"%ld",(secondCount / 60) % 60];
    if ([tmpmm length] == 1) {
        tmpmm = [NSString stringWithFormat:@"0%@",tmpmm];
    }
    
    // 秒
    NSString *tmpss = [NSString stringWithFormat:@"%ld",secondCount % 60];
    if ([tmpss length] == 1)
    {
        tmpss = [NSString stringWithFormat:@"0%@",tmpss];
    }
    
    //    NSLog(@"%@:%@", tmphh, tmpmm);
    return [NSString stringWithFormat:@"%@:%@:%@",tmphh,tmpmm,tmpss];
}

6 当需要在tableView中展示九宫格布局的情况:
比如

屏幕快照 2017-01-12 下午6.44.17.png

由于,此界面是由一个tableView构成的,现在要在原有的基础上添加添加一个子标题,点击后就是这种九宫格布局,为了在原因基础上搭建界面,最好在tableViewCell中嵌套一个collectionView,用collectionViewCell展示每一个九宫格数据,而且这样tableView直接把数据源给collectionView,方便其展示数据:

  • 首先tableViewCell只需要一个即可,将collectionView添加到- tableViewCell的contenView中,
  • 将collectionView的scrollEnabled设置为 NO,直接让tableView接受滚动事件,
  • 最后需要计算tableViewCell的高度,其实tableViewCell的高度就是collectionView的contentSize,如果每个collectionViewCell高度相同,高度根据数据源的个数,以及需要每行展示几个来计算,
    比如每行展示2个,那就是[ 行数(数据源的个数 / 2) * 每一行的高度],如果与2取余为1,也要加上一行

7 让创建出来的UILabel 上下左右有间隙

某些情况下,需要让UIlabel的上下左右有一定的间隙,有时候设置textAlignment并不能解决问题,比如文本已经设置了右对其了,但需求还是要让文本向左偏移一些,以下方法即可解决

解决方法:创建UILabel的子类使其能够让文字有上下左右的空隙,通过drawTextInRect方法实现

@implementation XYUserHomePageViewContentLabel {
    UIEdgeInsets _insets;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        self.textColor = kColorNameTextBlack;
        self.font = kFontWithSize(15);
        self.textAlignment = NSTextAlignmentRight;
        self.backgroundColor = [UIColor whiteColor];
        //  根据情况设置UIEdgeInsets _insets属性
        //  让文本向左偏移15的距离
        _insets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 10.0f);

    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, _insets)];
}

8 自定义导航条后,侧滑手势失效问题:
8.1 第一种情况:恢复系统默认的侧滑手势
第一步:自定义一个导航栏,并重写它的 viewDidLoad方法

系统默认的手势为interactivePopGestureRecognizer 当导航控制器响应的默认手势时,我们就重新设置手势的代理不再是系统的 UINavagtionController,而是我们自定义的这个导航控制器 , 再设置导航控制器的代理为它自己,因为一会还要监听它自己的代理方法

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = weakSelf;
        self.delegate = weakSelf;
    }
}

第二步 :重写导航控制器的pushViewController方法

重写 push 方法最主要的目的是让这个 pop 手势在 push 的时候变为不可用,因为可能在 push 过程中用户很快的进行了左滑动,那么就会造成 pop 栈中的混乱,导致画面卡顿,所以为了避免这个情况,我们必须要设置在 Push 过程中禁止这个手势的响应

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    if (self.childViewControllers.count > 0) {
        [viewController setHidesBottomBarWhenPushed:YES];
        
        // 自定义导航条左侧返回按钮
        UIButton *backBarButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [backBarButton setImage:[UIImage imageNamed:@"Login_backSel"].xy_originalMode forState:UIControlStateNormal];
        backBarButton.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
        [backBarButton sizeToFit];
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backBarButton];
        
        // 如果自定义返回按钮后,
        if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
            self.interactivePopGestureRecognizer.enabled = NO;
        }
        
    }
    
    [super pushViewController:viewController animated:animated];
}

第三步 :监听导航控制器 是否显示完毕 的 代理方法

这个方法主要是监听导航栏是否显示完毕,当显示完毕的时候我们要进行一个判断,因为当控制器ViewController 数量为1的时候,用户如果进行了右滑,但问题是当前控制器数量只有一个,那个这个方法 POP 什么呢?根本就没法 POP 嘛,也会造成了 pop 栈中的混乱,导致画面一直卡顿,所以我们也要进行一个判断,判断控制器数量只有一个的时候,我们就禁止了这个手势,反之则开启

#pragma mark - UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    if (navigationController.childViewControllers.count == 1) {
        self.interactivePopGestureRecognizer.enabled = NO;
    } else {
        self.interactivePopGestureRecognizer.enabled = YES;
    }
}

当然,我们在自定义的导航条的左侧返回按钮时,监听返回的方法中,最好让返回按钮判断当前是 push 还是 modal显示的,根据当前情况进行 pop 和 disMiss

- (void)backBarButton {
    
    // 判断两种情况: push 和 present
    if ([self isPresent]) {
        [self dismissViewControllerAnimated:YES completion:^{
        }];
    }else {
        [[self navigationController] popViewControllerAnimated:YES];
    }
    
}

- (BOOL)isPresent {
    
    BOOL isPresent;
    
    NSArray *viewcontrollers = self.viewControllers;
    
    if (viewcontrollers.count > 1) {
        if ([viewcontrollers objectAtIndex:viewcontrollers.count - 1] == self) {
            
            isPresent = NO; //push方式
        }
    }
    else{
        isPresent = YES;  // modal方式
    }
    
    return isPresent;
}

8.2 第二种情况,全屏滑动返回

自定义导航控制器

- (void)viewDidLoad {
    [super viewDidLoad];
 
    id target = self.interactivePopGestureRecognizer.delegate;
    self.interactivePopGestureRecognizer.enabled = NO;
    // 全屏滑动返回手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
    
    [self.view addGestureRecognizer:pan];
    
    pan.delegate = self;
   
    self.interactivePopGestureRecognizer.enabled = NO;
}
- (void)pushViewController:(XYProfileBaseController *)viewController animated:(BOOL)animated {

    if ([viewController isKindOfClass:[XYProfileBaseController class]]) {
        if (viewController.isHiddenLeftButton) {
            
            viewController.hiddenLeftButton = self.childViewControllers.count < 1;
        }
        if (self.childViewControllers.count) {
            viewController.hidesBottomBarWhenPushed = YES;
            viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:viewController action:@selector(leftBtnClick:)];
        }
    }
    [super pushViewController:viewController animated:animated];
}

#pragma mark - <UIGestureRecognizerDelegate>
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {

    return self.viewControllers.count > 1;
}

9 项目中app账号与环信账号的管理 - 登录

第一种方法:只需要iOS与环信交互:用户在我们的app注册会员的时候,注册成功获得返回值,正确的返回值内去注册环信账号,而环信账号就是用户注册app的账号的uid,密码是写死的,例如wiox8YvKZd23bbIYw,任何用户注册时,传给环信的密码都是相同的,这样方便登录。如果环信返回给你是注册成功,此时需要在成功里创建NSUserDeafults存储你的环信账号,密码就不用存了,并且调用环信登录方法。每次登录时公司在环信的账号会返回access_token、user信息及expires_in。登录时,公司服务器也会返回一个登录信息的json,登录成功时其中就有imUser即时通讯账号,使用imUser登录环信用户账号密码即可。
如果不在AppDelegate里写登录,你的APP如果退出了,下次打开就没用了,所以必须时时刻刻登录。所以你需要在AppDelegate登录,账号就是你本地存储的账号。密码还是死的。如果正常流程来说就是:

1.注册自己APP账号-成功-注册环信账号,密码为死的-成功-登录环信账号。

2.登录自己APP账号-成功-登录环信

3.AppDelegate存储账号。

第二种方法:让iOS,服务器,环信交互:通过上面的那种方式,跟服务器唯一交互的就是密码,你需要在用户注册你自己产品的时候,密码也注册环信。注册成功,将密码post给服务器,登录的时候成功,服务器不光返回error,msg,还要加一个环信的password,这样你拿到password 可以再进行登录。当然注册的时候Phone和Password需都需要存储,方便在AppDelegate入口类登录。

1.注册自己APP账号-成功-注册环信账号,密码为注册APP的密码-成功-Post密码给服务器-成功-登录环信账号。
2.登录自己APP账号-成功-拿到服务器返回的Password,登录环信账号-成功。
3.AppDelegate存储账号和密码

// 在app启动后调用登录IM

- (void)loginImUserAccount {
    
    // 读取用户登录后存储的登录信息
    NSDictionary *loginInfo  = [NSDictionary dictionaryWithContentsOfFile:kLoginInfoPath];
    XYLoginInfoItem *item = [XYLoginInfoItem loginInfoItemWithDict:loginInfo];
    
    // EMOptions设置配置信息 AppKey:注册环信的AppKey。
    EMOptions *options = [EMOptions optionsWithAppkey:@"wuwo#ziwo"];
    //apnsCertName:推送证书名(不需要加后缀)
    options.apnsCertName = @"MeSelf_APNS_DistriBution";
    // 初始化SDK
    EMError *error = [[EMClient sharedClient] initializeSDKWithOptions:options];
    if (!error) {
        NSLog(@"初始化成功");
    }
    
    // 使用用户登录成功后,使用公司服务端返回imUser账号登录环信
    error = [[EMClient sharedClient] loginWithUsername:item.iyidamUser.username password:item.imUser.password];
    if (!error) {
        NSLog(@"登录成功");
    } else {
        NSLog(@"登录失败-%@", error.errorDescription);
    }

}

10 集成环信 3.2.3 相关问题
10.1 使用EaseUI 报错问题解决:

当把EaseUI拖入到项目后进行编译,后报很多错误: 比如连UIKit及NSString都找不到, 这是因为EaseUI中加入了.c文件,属于混编报错,等于把PCH中的代码都拷贝一份到.c文件中了,需要给导入到OC的文件加OBJC

解决方法:

  1. 在pch文件中在所有代码的头部加入#ifdef __OBJC__尾部加入 #endif
    如下:
#ifdef __OBJC__

// 中间放 之前所有的 代码

#endif```

2.环信内部集成的MBProgressHUD   SDWebImage MJRefresh 与我们工程中集成的这几个第三方库发生冲突!删掉工程中自己集成的这些第三方库,或者删除环信EaseUI 里面的这些第三方库! 
需要注意的是:如果删除的是环信集成的第三方库!由于环信在集成的第三方库中加了EM前缀! 记得删掉EaseUI 中使用方法的前缀,不然会报错!
[官方集成视频地址](http://www.imgeek.org/video/23)

10.2 聊天会话页面更换用户头像和昵称

![WechatIMG2.jpeg](http://upload-images.jianshu.io/upload_images/2135374-9f4e0d13aa7145d0.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
经查看环信官网文档:
解决方法:在EaseMessageViewController或其子类方法中设置其数据源EaseMessageViewControllerDataSource,在以下数据源方法中 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像。

pragma mark - EaseMessageViewControllerDataSource

/*!
@method
@brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
@discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
@param viewController 当前消息视图
@param EMMessage 聊天消息对象类型
@result 返回<IMessageModel>协议的类型
*/

  • (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
    modelForMessage:(EMMessage *)message
    {
    //用户可以根据自己的用户体系,根据message设置用户昵称和头像
    id<IMessageModel> model = nil;
    model = [[EaseMessageModel alloc] initWithMessage:message];
    // 根据头像所在的用户是否为发送方,设置对应的模型数据
    if (model.isSender) { // 发送方
    model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
    // 设置消息消息发送方的头像和昵称
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate ;

      model.avatarURLPath = [appDelegate.currentloginInfo.basePath stringByAppendingString:appDelegate.currentloginInfo.userInfo.head]; //头像网络地址
      model.nickname = appDelegate.currentloginInfo.userInfo.name;//用户昵称
    

    } else {
    // 设置消息接收方的头像和昵称
    model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
    model.avatarURLPath = self.user.headFullURL.absoluteString;//头像网络地址
    model.nickname = self.user.name;//用户昵称
    }

    return model;
    }


10 集成友盟第三方登录
当第三方授权成功后,使用第三方平台获取的相关字段,再给服务器发送登录(一般需传入deviceToken、head、name、openPlatform、openPlatformId、os、osVersion、phoneModel、versionCode ),获取用户的loginInfo信息,服务器返回的code码为success为,就可以切换跟控制器了,再将loginInfo写入到本地保存,每次进入app后取出loginInfo进行判断用户是否登录,然后切换正确的跟控制器。

11 点赞、关注等接口的实现
当用户点赞时给服务器发送请求,传入相应的字段,当服务器响应成功时,根据code码判断是否点赞成功;当服务器返回的code为0时,点赞成功,此时应该修改对应的模型数据(比如把模型的isPraise修改为YES,点赞数据+1), 再调用reloadData刷新表格,在cell的模型的set方法中进行设置按钮的选中状态和按钮是否可以响应事件.

11 当界面需要按照服务端返回的前十个模型进行暂时排行榜单时,并且服务端并未返回排名
解决方法:首先给模型添加一个扩展属性ranking,用于作为榜单的id,在请求服务器数据完成时,开启子线程对数据进行处理,给前10个数据在模型中给ranking赋值,这里需要对数据源进行遍历,所以最好开启子线程处理,当处理到第10个数据时,停止遍历,并回到主线程中,刷新数据
代码如下:

/// 对模型进行处理 -- 为榜单前10个模型扩展排名属性

  • (void)processingModel:(void(^)())block {

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

      // 榜单数据
      if (self.currentType == XYTopicTypeNewRanklist) {
          NSInteger i = 0;
          BOOL flag = YES;
          while (flag) {
              if (i>_dataList[@(self.currentType)].count-1 || _dataList[@(self.currentType)].count == 0) {
                  flag = NO;
                  break;
              } else {
                  XYTopicViewModel *viewModel = _dataList[@(self.currentType)][i];
                  viewModel.item.ranking = [NSString stringWithFormat:@"    NO.%ld", i+1];
                  if (i == 9) {
                      flag = NO;
                      break;
                  }
                  i++;
              }
          }
          // 要回到主线程中刷新数据源,不然会引发莫名其妙的更新榜单不显示的问题
           [[NSOperationQueue mainQueue] addOperationWithBlock:^{
               if (block) {
                   block();
               }
           }];
    
          // 其他请求,也要回到主线程中
      } else  {
          [[NSOperationQueue mainQueue] addOperationWithBlock:^{
              if (block) {
                  block();
              }
          }];
      }
    

    });
    }


12 OC项目中怎么创建Swift文件及OC与Swift代码之间互相调用
首先在OC项目中创建一个类,Language选择为Swift,创建后会弹出一个桥接文件,点击创建即可,此时会产生一个```项目名-Bridging-Header.h```,此文件是为了swift代码中使用oc代码准备的桥接文件,如果swift想要使用oc的某个类,直接在这个桥接文件中导入oc头文件即可。
在OC需要使用到Swift类的类中导入```项目名-Swift.h```,然后就可以互相调用了,

13 Swift中获取String 字符串的长度
String结构体中没有Length的方法,但是可以通过Sting的扩展属性成员characters的count属性来获取

let title : String = "title"
let count = title.characters.count //获取String字符串的长度
print(count)


13 当导航控制器下的tableView的偏移量出现了问题时:
我设置了tableView的contentInset但是并未触发scrollViewDidScroll事件,虽然contentInset没有问题,但是导致初次进入界面时tableView的偏移量不对

self.automaticallyAdjustsScrollViewInsets = false
tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0)

所以手动设置tableView.contentOffset

tableView.setContentOffset(CGPoint.init(x: 0, y: -64), animated: true)


14 Swift中使用Masonry布局的代码格式:

headerLine.mas_makeConstraints { (make) in
make?.left.right().equalTo()(self)?.setOffset(0)
make?.bottom.equalTo()(self)?.setOffset(-margin)
make?.height.equalTo()(44)
}
figureSpecialView.mas_makeConstraints { (make) in
make?.top.left().right().equalTo()(self)?.setOffset(0)
make?.bottom.equalTo()(self.headerLine.mas_top)?.setOffset(-margin)

    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 1.手势操作,单击双击的区分 记得在作为delegate的view的头文件加上 tapRecognizer.max...
    青鸟evergreen阅读 121评论 0 0
  • 1.badgeVaule气泡提示 2.git终端命令方法> pwd查看全部 >cd>ls >之后桌面找到文件夹内容...
    i得深刻方得S阅读 4,628评论 1 9
  • 六.集成SDK基础功能 (仔细研习,结合实际操作) 由于环信官方文档比较详细,因此,根据项目需求,把用到的方法记录...
    夜空已沉寂阅读 2,138评论 0 7
  • 2001年的元旦刚过,我还没来得及去上班,就接到广东省公安边防武警总队的副总队长的电话,他说要我明天回单位开...
    叔泰szy阅读 441评论 0 1