[iOS] How to sort an NSMutableArray with custom objects in it?


I think this will do it:

brandDescriptor = [[NSSortDescriptor alloc] initWithKey:@"brand" ascending:YES];
sortDescriptors = [NSArray arrayWithObject:brandDescriptor];
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];

I pulled the code from Sort Descriptor Programming Topics. Also, Key-Value Coding comes into play, in that sortedArrayUsingDescriptors: will send a valueForKey: to each element in myArray, and then use standard comparators to sort the returned values.



Compare method

Either you implement a compare-method for your object:

- (NSComparisonResult)compare:(Person *)otherObject {
    return [self.birthDate compare:otherObject.birthDate];

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];

NSSortDescriptor (better)

or usually even better:

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

You can easily sort by multiple keys by adding more than one to the array. Using custom comparator-methods is possible as well. Have a look at the documentation.

Blocks (shiny!)

There’s also the possibility of sorting with a block since Mac OS X 10.6 and iOS 4:

NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate *first = [(Person*)a birthDate];
    NSDate *second = [(Person*)b birthDate];
    return [first compare:second];


The -compare: and block-based methods will be quite a bit faster, in general, than using NSSortDescriptor as the latter relies on KVC. The primary advantage of the NSSortDescriptormethod is that it provides a way to define your sort order using data, rather than code, which makes it easy to e.g. set things up so users can sort an NSTableView by clicking on the header row.



[iOS] UIStoryboardSegue detecting table cell and opening a viewController?

在完成了 「客製化TableViewCell (Custom TableViewCell)」,接下來需要把參數帶到下一個view 裡。方法還滿多的。

This question seems to be very popular here on stackoverflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.

I hope this answer is clear enough for people to understand and that I have not missed anything.

Passing Data Forward

Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.

For this example we will have ViewControllerA and ViewControllerB

To pass a BOOL value from ViewControllerA to ViewControllerB we would do the following.

  1. in ViewControllerB.h create a property for the BOOL
    @property(nonatomic) BOOL *isSomethingEnabled;
  2. in ViewControllerA you need to tell it about ViewControllerB so use an
    #import "ViewControllerB.h"

    Then where you want to load the view eg. didSelectRowAtIndex or some IBAction you need to set the property in ViewControllerB before you push it onto nav stack.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];

    This will set isSomethingEnabled in ViewControllerB to BOOL value YES.

Passing Data Forward using Segues

If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

So to pass a BOOL from ViewControllerA to ViewControllerB we would do the following:

  1. in ViewControllerB.h create a property for the BOOL
    @property(nonatomic) BOOL *isSomethingEnabled;
  2. in ViewControllerA you need to tell it about ViewControllerB so use an
    #import "ViewControllerB.h"
  3. Create a the segue from ViewControllerA to ViewControllerB on the storyboard and give it an identifier, in this example we’ll call it "showDetailSegue"
  4. Next we need to add the method to ViewControllerA that is called when any segue is performed, because of this we need to detect which segue was called and then do something. In our example we will check for "showDetailSegue" and if thats performed we will pass our BOOL value to ViewControllerB
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;

    If you have your views embedded in a navigation controller you need to change the method above slightly to the following

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;

    This will set isSomethingEnabled in ViewControllerB to BOOL value YES.

Passing Data Back

To pass data back from ViewControllerB to ViewControllerA you need to use Protocols and Delegates or Blocks, the latter can be used as a loosely coupled mechanism for callbacks.

To do this we will make ViewControllerA a delegate of ViewControllerB. This allows ViewControllerB to send a message back to ViewControllerA enabling us to send data back.

For ViewControllerA to be delegate of ViewControllerB it must conform to ViewControllerB‘s protocol which we have to specify. This tells ViewControllerA which methods it must implement.

  1. In ViewControllerB.h, below the #import, but above @interface you specify the protocol.
    @class ViewControllerB;
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
  2. next still in the ViewControllerB.h you need to setup a delegate property and synthesize in ViewControllerB.m
    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. In ViewControllerB we call a message on the delegate when we pop the view controller.
    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. That’s it for ViewControllerB. Now in ViewControllerA.h, tell ViewControllerA to import ViewControllerB and conform to its protocol.
    #import "ViewControllerB.h"
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. In ViewControllerA.m implement the following method from our protocol
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
        NSLog(@"This was returned from ViewControllerB %@",item);
  6. Before pushing viewControllerB to navigation stack we need to tell ViewControllerB that ViewControllerA is its delegate, otherwise we will get an error.
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];


Further Help


iOS – UIStoryboardSegue detecting table cell and opening a viewController?

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    // Assume self.view is the table view
    NSIndexPath *path = [self.tableView indexPathForSelectedRow];
    DetailObject *detail = [self detailForIndexPath:path];
    [segue.destinationViewController setDetail:detail];

UITableView “selection” triggered segue


How to make a push segue when a UITableViewCell is selected

drag From View Controller to View Controller


You will need to give an identifier to your segue:

enter image description here

Perform the segue:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    [self performSegueWithIdentifier:@"yourSegue" sender:self];

Now here is the thing, this will just perform the segue, if you ever needed to pass some data to that view controller. Then you have to implement the following segue delegate:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"yourSegue"])
        //if you need to pass data to the next controller do it here

[iOS] clang: error: linker command failed with exit code 1 (use -v to see invocation)

按照別人寫的sample code 完成了客製化tableview 之後:

程式碼裡,一定不只一個 tableview,  在只有一個 tableview 情況下不會出錯,但多個 tableview  無法build. 原因在變數名稱重覆,第1次遇到這個 error.

發生的原因在 變數的 scope 重覆:

@implementation SimpleTableViewController

NSArray *tableData;

- (void)viewDidLoad

把 tableData 改放到

@interface SimpleTableViewController



[iOS] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

這篇超容易踩到的,除了使用 http 會遇到,連使用https 也會遇到,如果沒去設定而且連到 https 的網站,會顯示這一個  Error:

Error Domain=NSURLErrorDomain Code=-1200 “An SSL error has occurred and a secure connection to the server cannot be made


If you try to make HTTP requests with ATS enabled (using NSURLSession or libraries like AFNetworking), you’ll see errors like this.

Here’s how to disable ATS entirely. Open Info.plist, and add the following lines:


You have to add just the NSAllowsArbitraryLoads key to YES in NSAppTransportSecurity dictionary in your info.plist file.



[iOS] Loading Image from URL iOS

NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];

I will just adapt Jim Dovey answer from here Getting Image from URL Objective C :

Synchronous version

NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"http://myurl/mypic.jpg"]];
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageWithData: imageData]];

Asynchronous version

dispatch_async(dispatch_get_global_queue(0,0), ^{
    NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"http://myurl/mypic.jpg"]];
    if ( data == nil )
    dispatch_async(dispatch_get_main_queue(), ^{
        UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageWithData: data]];

[iOS] UIApplication內建服務的openURL


 NSURL *appURL = [NSURL URLWithString:@"line://msg/text/IamHappyMan:)"];
 if ([[UIApplication sharedApplication] canOpenURL: appURL]) {
 [[UIApplication sharedApplication] openURL: appURL];
 else { //如果使用者沒有安裝,連結到App Store
 NSURL *itunesURL = [NSURL URLWithString:@"itms-apps://itunes.apple.com/app/id443904275"];
 [[UIApplication sharedApplication] openURL:itunesURL];

分享Line要注意的是:必須將<CONTENT KEY>的內容轉成UTF-8,


/* Adds all percent escapes necessary to convert the receiver into a legal URL string.  Uses the given encoding to determine the correct percent escapes (returning nil if the given encoding cannot encode a particular character).  See CFURLCreateStringByAddingPercentEscapes in CFURL.h for more complex transformations


– (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc;


UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"happyman.jpg"]];
[pasteboard setData:UIImageJPEGRepresentation(imageView.image, 0.9) forPasteboardType:@"public.jpeg"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"line://msg/image/%@", pasteboard.name]];
[[UIApplication sharedApplication] openURL: url];

在 iOS 10中 openURL 的新方法:

// Objective-C
- (void)openURL:(NSURL*)url options:(NSDictionary *)options
 completionHandler:(void (^ __nullable)(BOOL success))completion
// Swift
open func open(_ url: URL, options: [String : Any] = [:],
 completionHandler completion: (@escaping (Bool) -> Swift.Void)? = nil)




– (BOOL)openURL:(NSURL*)url NS_DEPRECATED_IOS(2_0, 10_0, “Please use openURL:options:completionHandler: instead”) NS_EXTENSION_UNAVAILABLE_IOS(“”);

– (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0);

下面範例是 swift, 但大多 objective-c 應該也是通用。

版本:Xcode 7.0.1 + Swift 2

let sms: String = “sms:0912666999”
UIApplication.sharedApplication().openURL(NSURL(string: sms)!)

let tel: String = “tel:0912666999”
UIApplication.sharedApplication().openURL(NSURL(string: tel)!)

let url: String = “http://www.apple.com”
UIApplication.sharedApplication().openURL(NSURL(string: url)!)

開啟 App Store
// id791084265 => id軟體編號(AppleID)
let appStoreUrl: NSURL = NSURL(string: “itms-apps://itunes.apple.com/app/id791084265”)!

// itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=AppleID
let str = “itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=791084265”
let url: NSURL = NSURL(string: str)!

呼叫 Line

// b. Xcode 撰寫
let text: String! = “HappyBirthday生日快樂!!”
// 設定文字編碼,防止Line無法讀取中文
let encodeMessage: String! = text.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
var lineURL = NSURL(string: “line://msg/text/” + encodeMessage)

if UIApplication.sharedApplication().canOpenURL(lineURL!) {
} else {
lineURL = NSURL(string: “itms-apps://itunes.apple.com/app/id443904275”)!

// URL模式:http://maps.google.com/maps?q=<strong>${QUERY_STRING}</strong>
let address = “高雄市三多三路214-15號”
let urlString = “http://maps.google.com/maps?q=\(address)”

// 處理編碼
let encodeMessage: String! = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
let url: NSURL = NSURL(string: encodeMessage)!


[iOS] How to round the corners of a button



實作出來的效果,我是用 cornerRadius = 5


You can manipulate the CALayer of your button to do this pretty easily.

// assuming you have a UIButton or more generally a UIView called buyButton

buyButton.layer.cornerRadius = 2;
buyButton.layer.borderWidth = 1;
buyButton.layer.borderColor = [UIColor blueColor].CGColor;
// (note - may prefer to use the tintColor of the control)

you can tweak each of those to get the color and border effect you want.

You will also have to add an import in any file you want to use CALayers

#import <QuartzCore/QuartzCore.h>




iOS 7 round framed button

How to round the corners of a button

No Round Rect Button in Xcode 5?

[iOS] 客製化TableViewCell (Custom TableViewCell)

客製化TableViewCell, 照著這3篇做,就成功了,還滿簡單的。

[iOS] 客製化TableViewCell (Custom TableViewCell)

Customize Table View Cells for UITableView

Customize Table View Cells for UITableView in iOS





- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 static NSString *simpleTableIdentifier = @"SimpleTableItem";
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
 if (cell == nil) {
 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
 cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
 cell.imageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
 return cell;



#pragma mark - TableView events

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
 // Return the number of sections.
 return 1;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
 return [userArray count];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 static NSString *CellIdentifier = @"IMUserCell";
 //UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 IMUserCell *cell = (IMUserCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil){
 NSArray *cells = [[NSBundle mainBundle] loadNibNamed:@"IMUserCell" owner:self options:nil];
 cell = [cells objectAtIndex:0];
 //Configure the cell.
 //cell.textLabel.text = [self.colorNames objectAtIndex:[indexPath row]];
 UserInfo *user = [userArray objectAtIndex:[indexPath row]];
 [cell.textLineID setText:user.line_id];
 [cell.textCountry setText:user.country_code];
 [cell.textMessage setText:user.message];
 if(user.tag1 && user.tag1.length > 0) {
 NSString *gameTitle = NSLocalizedString(user.tag1, nil);
 cell.btnTag1.layer.cornerRadius = 5;
 [cell.btnTag1 setTitle:gameTitle forState:UIControlStateNormal];
 [cell.btnTag1 setHidden:YES];
 if(user.tag2 && user.tag2.length > 0) {
 NSString *gameTitle = NSLocalizedString(user.tag2, nil);
 cell.btnTag2.layer.cornerRadius = 5;
 [cell.btnTag2 setTitle:gameTitle forState:UIControlStateNormal];
 [cell.btnTag2 setHidden:YES];
 cell.userPhoto.image = [UIImage imageNamed:@"icon_user_photo_default.png"];

 return cell;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 return 60;

[iOS] objective c getting substring after and before dot


NSString *str = yourstr; 
NSArray *Array = [str componentsSeparatedByString:@"."]; 
NSString *t = [Array objectAtIndex:0]; 
NSString *t1 = [Array objectAtindex:1]; 

NSString *myString = @"app://ga/ecommerce/product:playstation4"; 
NSArray* spliteArray = [myString componentsSeparatedByString: @"/"];
NSString* lastString = [spliteArray lastObject];


[iOS] How do I check if a string contains another string in Objective-C?

NSString *string = @"hello bla bla";
if ([string rangeOfString:@"bla"].location == NSNotFound) {
  NSLog(@"string does not contain bla");
} else {
  NSLog(@"string contains bla!");

The key is noticing that rangeOfString: returns an NSRange struct, and the documentation says that it returns the struct {NSNotFound, 0} if the “haystack” does not contain the “needle”.

And if you’re on iOS 8 or OS X Yosemite, you can now do: (*NOTE: This WILL crash your app if this code is called on an iOS7 device).

NSString *string = @"hello bla blah";
if ([string containsString:@"bla"]) {
  NSLog(@"string contains bla!");
} else {
  NSLog(@"string does not contain bla");