Posts match “ iOS ” tag:

Dismissing UIAlertView After Some Time

To dismissing a UIAlertView after 1.5 sec.

[self performSelector:@selector(dismissAfterDelay) withObject:nil afterDelay:1.5];
- (void)dismissAfterDelay
{
  [self.alertView dismissWithClickedButtonIndex:0 animated:YES];
}

Using lastObject to get dynamic content size of UIScrollView

UIScrollView *uiscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];

// add subview
[uiscrollview addSubview:[self addImage:UIViewContentModeScaleToFill :CGPointMake(20, 44) :CGSizeMake(280, 280)]];
[uiscrollview addSubview:[self addImage:UIViewContentModeScaleAspectFit :CGPointMake(20, 334) :CGSizeMake(280, 280)]];
[uiscrollview addSubview:[self addImage:UIViewContentModeScaleAspectFill :CGPointMake(20, 624) :CGSizeMake(280, 280)]];
[uiscrollview addSubview:[self addImage:UIViewContentModeTopLeft :CGPointMake(20, 914) :CGSizeMake(280, 280)]];

// get dynamic content size
UIView *lo = [uiscrollview.subviews lastObject];
NSInteger oy = lo.frame.origin.y;
NSInteger ht = lo.frame.size.height;
uiscrollview.contentSize = CGSizeMake(uiscrollview.frame.size.width, oy + ht);

[self.view addSubview:uiscrollview];

Resizing UIImage in iOS

-(UIImage*)resizeImage:(UIImage *)image imageSize:(CGSize)size
{
  //http://stackoverflow.com/questions/18956611/programmatically-screenshot-works-bad-on-ios-7
  //UIGraphicsBeginImageContext(size);
  UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
  [image drawInRect:CGRectMake(0,0,size.width,size.height)];
  UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return newImage;  
}

What is UIViewContentMode

UIViewContentMode

typedef NS_ENUM(NSInteger, UIViewContentMode) {
    UIViewContentModeScaleToFill,
    UIViewContentModeScaleAspectFit,  // contents scaled to fit with fixed aspect. remainder is transparent
    UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped.
    UIViewContentModeRedraw,          // redraw on bounds change (calls -setNeedsDisplay)
    UIViewContentModeCenter,          // contents remain same size. positioned adjusted.
    UIViewContentModeTop,
    UIViewContentModeBottom,
    UIViewContentModeLeft,
    UIViewContentModeRight,
    UIViewContentModeTopLeft,
    UIViewContentModeTopRight,
    UIViewContentModeBottomLeft,
    UIViewContentModeBottomRight,
};

舉例來說要將原圖(512x512)放入280x160的顯示區塊

原圖

不同的 ContentMode 會有不同的效果,說明如下:

  • ScaleToFill: 比例會跑掉。
  • ScaleAspectFit: 維持比例放入整張圖,周圍會留白。
  • ScaleAspectFill: 維持比例置中放入圖片,多餘的部份會被卡掉。
  • ScaleAspectFill+AlignTopLeft: 維持圖片比例,但要置上,也就是卡掉下方多餘的部份。

ScaleAspectFill+AlignTopLeft 實作如下:

UIImage *uiimage = [UIImage imageNamed:@"origin.png"];
// 設定顯示區塊
UIImageView *uiimageview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 280, 160)];
uiimageview.contentMode = UIViewContentModeTopLeft;
// 卡掉多餘的部份
uiimageview.clipsToBounds = YES;
// resize image to 280x280
uiimageview.image = [self resizeImage:uiimage imageSize:CGSizeMake(280, 280) ];

Read more about ContentMode.

Generating a Random Color in iOS

// RGB
UIColor *randomRGBColor = [[UIColor alloc] initWithRed:arc4random()%256/256.0 green:arc4random()%256/256.0 blue:arc4random()%256/256.0 alpha:1.0];

// HSB
UIColor *randomHSBColor = [[UIColor alloc] initWithHue:arc4random()%256/256.0 saturation:(arc4random()%128/256.0)+0.5 brightness:(arc4random()%128/256.0)+0.5 alpha:1.0];

iOS Packet Tracking via USB

Connect the iOS device to OSX via USB

Get UDID
system_profiler SPUSBDataType

Serial Number: XXXXXXXXXXXXXXXXXXXXXXXXXX

List
rvictl -l

Start
rvictl -s XXXXXXXXXXXXXXXXXXXXXXXXXX

Stop
rvictl -x XXXXXXXXXXXXXXXXXXXXXXXXXX

ifconfig -l
lo0 gif0 stf0 en0 en1 fw0 en3 p2p0 bridge0 rvi0

if you don't have the interface rvi0
ifconfig rvi0

Now you can run tcpdump.
tcpdump -i rvi0 -n -t -q -A tcp
tcpdump -i rvi0 -n -t -l -s 1024 -q -A 'tcp port 80' > tcpdump

Just for GoogleAnalytics-iOS-SDK 2.x

// realtime tracking
[GAI sharedInstance].dispatchInterval = 0;
// print debug messages
[GAI sharedInstance].debug = YES;
// disable https
[GAI sharedInstance].defaultTracker.useHttps = NO;

tcpdump
remote packet capture

MBProgressHUD

Recommended Way:

#import "MBProgressHUD.h"
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // do something...
    Service *service = [Service instance];
    [service resizeDownLoadImage];
    dispatch_async(dispatch_get_main_queue(), ^{
      // update main UI
      [hud removeFromSuperview];
      //UITableView/UICollectionView reloadData is synchronous call
      //[self.collectionview reloadData];
      [self presentMainViewController];
    });
});

Show Text Only:

MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = msg;
hud.margin = 10.f;
hud.yOffset = self.view.frame.size.height*0.5 - 15.f;
hud.removeFromSuperViewOnHide = YES;
// auto hide after 1 second
[hud hide:YES afterDelay:1];

How To Download Images Asynchronously for UITableView

  • CACHE
  • GCD
  • PLACEHOLDER
  • reloadRowsAtIndexPaths
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *cellIdentifier = @"TableCellReuseIdentifier";
  AWTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  if(!cell)
  {
    NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:@"AWTableCell" owner:self options:nil];
    cell = [nibs objectAtIndex:0];
  }
  AWCourse *node = [self.childrenNodes objectAtIndex:indexPath.row];
  // load image from cache
  if(node.thumbnail) {
    cell.imageView.image = node.thumbnail;
  }
  else {
    // add an image placeholder
    cell.imageView.image = [UIImage imageNamed:@"image_loading.png"];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
      // download and resize image
      UIImage *image = [self resizeImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:(node.type==1 ? node.picAudioUrl : node.picUrl)]]] imag$
      if(!cell.imageView) return;
      if(!tableView) return;
      dispatch_async(dispatch_get_main_queue(), ^{
        // cache image
        node.thumbnail = image;
        // Reloads the specified rows using a certain animation effect(fade or none).
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
      });
    });
  }

  return cell;
}

xctool

xctool

build

xctool -workspace Project.xcworkspace -scheme Project build
xctool -project  Project.xcodeproj -scheme Project build

clean & test

xctool -workspace Project.xcworkspace -scheme Project -sdk iphonesimulator clean test

a similar tool:

shenzhen

ipa build

Auto bump version for plist

#!/bin/sh

# Auto bump a version number for git
# ie: 1.1 -> 1.2
# Usage: bump.sh Project-Info.plist

if [ $# -ne 1 ]; then
  echo usage: $0 plist-file
  exit 1
fi

PLIST="$1"
DIR="$(dirname "$plist")"
VERSIONNUM=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${PLIST}")
DATE=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PLIST}")
NEWDATE=$(date "+%Y%m%d")

NEWSUBVERSION=`echo $VERSIONNUM | awk -F "." '{print $2}'`
NEWSUBVERSION=$(($NEWSUBVERSION + 1))
NEWVERSIONSTRING=`echo $VERSIONNUM | awk -F "." '{print $1 ".'$NEWSUBVERSION'" }'`

if [ -z "$VERSIONNUM" ]; then
  echo "No build number in $PLIST"
  exit 2
fi

echo "Git commit and release..."
git checkout -b release/$NEWVERSIONSTRING develop

echo "Bumped build number $VERSIONNUM -> $NEWVERSIONSTRING ($NEWDATE)"
/usr/libexec/Plistbuddy -c "Set :CFBundleShortVersionString $NEWVERSIONSTRING" "${PLIST}"
/usr/libexec/Plistbuddy -c "Set :CFBundleVersion $NEWDATE" "${PLIST}"

echo "Prepare for $NEWVERSIONSTRING"
git commit -a -m "Prepare for $NEWVERSIONSTRING"
git checkout master
git merge --no-ff release/$NEWVERSIONSTRING
git tag -a $NEWVERSIONSTRING -m "Added tag $NEWVERSIONSTRING"
git checkout develop
git merge --no-ff release/$NEWVERSIONSTRING
git branch -d release/$NEWVERSIONSTRING

echo "done..."

AFNetworking 2.X

AFHTTPRequestOperation

NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@",HOST,@"login.json"]];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__weak AFHTTPRequestOperation *woperation = operation;
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlock:^(){
  NSLog(@"response name:%@", [woperation.responseObject valueForKey:@"Name"]);
}];
[operation start];

AFHTTPRequestOperationManager

// GET /demo.json?token=lalalalalala&id=101
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:append(HOST, @"demo.json") parameters:@{@"token":@"lalalalalala", @"id":@"101"} success:^(AFHTTPRequestOperation *operation, id responseObject) {
  //NSLog(@"response:%@", responseObject);
  NSMutableArray *arr = [responseObject objectForKey:@"bodys"];
  NSLog(@"response name:%@", [[arr objectAtIndex:7] valueForKey:@"name"]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
  NSLog(@"error:%@", error);
}];

Content-Type: text/html

self.responseSerializer.acceptableContentTypes = [self.responseSerializer.acceptableContentTypes setByAddingObject:@"text/plain"];

json response

self.responseSerializer = [AFJSONResponseSerializer serializer];

Any response serializer dealing with HTTP

self.responseSerializer = [AFHTTPResponseSerializer serializer];

Convert NSNumber to NSTimeInterval

// double -> NSNumber
NSNumber *doubleTime = [NSNumber numberWithDouble:123.123123123];
// NSNumber -> NSTimerInterval = double
NSTimeInterval *timInterval = [doubleTime doubleValue];

pass data between view controllers using blocks

ViewA -> ViewB

ViewB

ViewControllerB.h
@property (nonatomic, copy) void(^complete)();
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil complete:(void(^)())completion;
ViewControllerB.m
#pragma mark - blocks
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil complete:(void(^)())completion {
  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  if(self) {
    _complete = completion;
  }
  return self;
}

// call block
- (void)viewDidDisappear:(BOOL)animated {
  [super viewDidDisappear:animated];  
  _complete();
}

ViewA

ViewControllerA.m
viewController = [[AWLobbyCollectionView alloc] initWithNibName:@"AWLobbyCollectionView" bundle:nil complete:^{
  NSLog(@"thie is complete block!!");
}];

UITextView issues in iOS6 and iOS7

UITextView is so buggy on iOS6/iOS7...

line spacing

// adjust lineSpacing
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.minimumLineHeight = LINE_HEIGHT;
style.maximumLineHeight = LINE_HEIGHT;
style.lineHeightMultiple = LINE_HEIGHT;
// Bug: NSFontAttributeName not working in ios6
NSDictionary *attributes = @{
                           NSParagraphStyleAttributeName : style,
                           };
[textView setAttributedText:[[NSAttributedString alloc] initWithString:content attributes:attributes]];

font size

//Fixed: font-size not working in ios6
[textView setEditable:YES];
[textView setFont:[UIFont fontWithName:@"Helvetica" size:FONT_SIZE]];
[textView setEditable:NO];

contentSize

// in iOS6
[textView sizeToFit];
NSLog(@"height:%f", [textView contentSize].height);

in iOS6
height: 416

not working in iOS7
height: 292

[textView setFrame:CGRectMake(10, 10, 300, [self measureHeightOfUITextView:textView])];
NSLog(@"height:%f", [self measureHeightOfUITextView:textView]);
- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
  return [textView sizeThatFits:CGSizeMake(textView.frame.size.width, FLT_MAX)].height;
}

Fixed:
in iOS6
height: 416

in iOS7
height: 366

Added a screenshot for the final results.

combining all code.
I also create an category for UITextView+Additions.

Compiling error after upgrading Xcode 5.1

missing required architecture arm64 blah blah blah...

5.1 後預設是包含 64 bit,造成編繹時會噴一堆 error,解決方法如下:

Projects -> Build Setting -> Architectures
$(ARCHS_STANDARD) -> $(ARCHS_STANDARD_32_BIT)

xctool 0.1.14 build failed

github issues 一堆人在靠腰,新版應該過幾天就會出來,等不及的人可以先手動指定。

-destination 'name=iPhone Retina (4-inch),OS=7.1'

更新 0.1.15 已修正這個問題。

Padding zero in NSString

A simple way

NSLog(@"padding space:%@",[NSString stringWithFormat:@"AA%6d",123]);
NSLog(@"padding zero:%@",[NSString stringWithFormat:@"AA%06d",123]);

//padding space:AA   123
//padding zero :AA000213

以上方式只能補空白或是0,如果要補其它字元呢?

NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setPaddingPosition:NSNumberFormatterPadBeforePrefix];
[formatter setPaddingCharacter:@"="];
[formatter setFormatWidth:6];
NSLog(@"%@", [NSString stringWithFormat:@"AA%@", [formatter stringFromNumber:@123]]);

//padding equals:AA===123

Getting a comma separated string from NSArray

NSArray *arr = @[@1,@2,@3,@"abc"];
NSLog(@"%@", arr);
NSLog(@"description:%@", [arr description]);
/*
兩種方式都輸出如下,被加上換行符號
(
    1,
    2,
    3,
    abc
)
*/

改成componentsJoinedByString

NSLog(@"%@", [arr componentsJoinedByString:@","]);
//1,2,3,abc

Fixing iOS7 status bar

真的會被 iOS7 status bar 搞瘋~~

storyboard 的解法可以看這篇

這篇是針對不使用 storyboard 的解法。

option1: 直接對 AppDelegate 動手

Info.plist
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
AppDelegate.m
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
  [application setStatusBarStyle:UIStatusBarStyleLightContent];
  self.window.clipsToBounds =YES;
  self.window.frame =  CGRectMake(0,20,self.window.frame.size.width,self.window.frame.size.height-20);
  //fixed scaling bugs - 可以試試 mark 掉下面這行的差別
  //self.window.bounds = CGRectMake(0, 20, self.window.frame.size.width, self.window.frame.size.height);
}

option2: viewDidLayoutSubviews

如有需要也可以針對特定的 view 調整 frame。

// fixing status bar in iOS7
- (void)viewDidAppear:(BOOL)animated
{
  [super viewDidAppear:animated];
  if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7"))
    self.view.frame = CGRectMake(0, -20, self.view.frame.size.width, self.view.frame.size.height);
}

// fixing status bar in iOS7
- (void)viewDidLayoutSubviews
{
  [super viewDidLayoutSubviews];
  if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7"))
    self.view.frame = CGRectMake(0, -20, self.view.frame.size.width, self.view.frame.size.height);
}

option3: Hiding status bar

或是乾脆隱藏...

BaseViewController.m
- (BOOL)prefersStatusBarHidden
{
  return YES;
}

Another issue

當使用presentViewController會將window.rootViewController.view往上推,新增一個方法來解決這個問題。
myUtil.m
+ (void)fixingStatusBarAfterPresenting:(UIViewController *)vc withAnimation:(BOOL)animation
{
  if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) {
    CGRect viewFrame = vc.view.frame;
    if(viewFrame.origin.y == 20) return;
    viewFrame.origin.y += 20.0;
    //已在 didFinishLaunchingWithOptions 處理過高度
    //viewFrame.size.height-= 20.0;
    if (animation == YES) {
      [UIView animateWithDuration:0.25 animations:^{
        vc.view.frame = viewFrame;
      }];
    }
    else vc.view.frame = viewFrame;    
    [vc.view layoutIfNeeded];
  }
}
解決 view 升起時,不要凸到 status bar 的位置。
myPresentViewController.m
- (void)viewDidLayoutSubviews
{
  [super viewDidLayoutSubviews];
  [TWECUtil fixingStatusBarAfterPresenting:self withAnimation:NO];
}
縮回去的時候,將 root view 調回來。
myPresentViewController.m
- (IBAction)onCancelBtnPressed:(id)sender
{
  [self dismissViewControllerAnimated:YES completion:^{
    TWECAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    [TWECUtil fixingStatusBarAfterPresenting:delegate.window.rootViewController withAnimation:YES];
  }];
}

參考資料1
參考資料2