Monday, April 11, 2016

[Jenkins] Install Xcode command line tools over SSH

  1. If you don't have a free Apple developer account, register for one
  2. Download the "Command Line Tools for Xcode" appropriate for your version of OSX
    For me, that was "Command Line Tools (OS X Mountain Lion) for Xcode - April 2014"
  3. Copy the dmg file to your remote
    In the following command, I'm using scp to securely copy the file from my local computer to the remote named remote
    $ scp ~/Downloads/command_line_tools_for_osx_mountain_lion_april_2014.dmg remote:Downloads/
  4. ssh to your remote
    $ ssh remote
  5. mount the dmg file on the remote
    Here, I'm using hdiutil to mount the image
    $ hdiutil attach ~/Downloads/command_line_tools_for_osx_mountain_lion_april_2014.dmg
  6. install the package contained in the dmg
    Here, installer must be run with sudo because this package needs to be installed on the root file system
    $ cd /Volumes/Command\ Line\ Tools\ \(Mountain\ Lion\)
    $ sudo installer -pkg Command\ Line\ Tools\ \(Mountain\ Lion\).mpkg -target /
  7. unmount the dmg file
    $ hdiutil detach /Volumes/Command\ Line\ Tools\ \(Mountain\ Lion\)
  8. delete the dmg file from the remote; optional
    I see no purpose keeping it around, but you can if you want.
    $ rm ~/Downloads/command_line_tools_for_osx_mountain_lion_april_2014.dmg
  9. Use the below to agree to the Xcode/iOS license:
    sudo xcodebuild -license

Wednesday, April 6, 2016

[iOS] Include of non-modular header inside framework module


When there are framework classes depend on the class in the project that you are working on in Xcode, it usually shows error as "Class can't be found from the framework lib". Then you can fix it by: 

Setting Allow Non-modular includes in Framework Modules in Build Settings for the affected target to YES. This is the build setting you need to edit:

Tuesday, March 22, 2016

[iOS] Useful Collection Operators

@avg

The @avg operator uses valueForKeyPath: to get the values specified by the property specified by the key path to the right of the operator, converts each to a double, and returns the average value as an instance of NSNumber. In the case where the value is nil0 is assumed instead.
The following example returns the average value of the transaction amount for the objects in transactions:
NSNumber *transactionAverage = [transactions valueForKeyPath:@"@avg.amount"];
The formatted result of transactionAverage is $456.54.

@count

The @count operator returns the number of objects in the left key path collection as an instance of NSNumber, the key path to the right of the operator is ignored.
The following example returns the number of Transaction objects in transactions:
NSNumber *numberOfTransactions = [transactions valueForKeyPath:@"@count"];
The value of numberOfTransactions is 13.

@max

The @max operator compares the values of the property specified by the key path to the right of the operator and returns the maximum value found. The maximum value is determined using the compare: method of the objects at the specified key path. The compared property objects must support comparison with each other. If the value of the right side of the key path is nil, it is ignored.
The following example returns the maximum value of the date values (date of the latest transaction) for the Transaction objects intransactions:
NSDate *latestDate = [transactions valueForKeyPath:@"@max.date"];
The latestDate value (formatted) is Jul 15, 2010.

@min

The @min operator compares the values of the property specified by the key path to the right of the operator and returns the minimum value found. The minimum value is determined using the compare: method of the objects at the specified key path. The compared property objects must support comparison with each other. If the value of the right side of the key path is nil, it is ignored.
The following example returns the minimum value (date of the earliest transaction) of the date property for the Transaction objects intransactions:
NSDate *earliestDate = [transactions valueForKeyPath:@"@min.date"];
The earliestDate value (formatted) is Dec 1, 2009.

@sum

The @sum operator returns the sum of the values of the property specified by the key path to the right of the operator. Each number is converted to a double, the sum of the values is computed, and the total is wrapped as an instance of NSNumber and returned. If the value of the right side of the key path is nil, it is ignored.
The following example returns the sum of the amounts property for the transactions in transactions:
NSNumber *amountSum = [transactions valueForKeyPath:@"@sum.amount"];
The resulting amountSum value (formatted) is $5,935.00.

@distinctUnionOfObjects

The @distinctUnionOfObjects operator returns an array containing the distinct objects in the property specified by the key path to the right of the operator.
The following example returns the payee property values for the transactions in transactions with any duplicate values removed:
NSArray *payees = [transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];
The resulting payees array contains the following strings: Car Loan, General Cable, Animal Hospital, Green Power, Mortgage.
The @unionOfObjects operator is similar, but does not remove duplicate objects.


@unionOfObjects

The @unionOfObjects operator returns an array containing the distinct objects in the property specified by the key path to the right of the operator. Unlike @distinctUnionOfObjects, duplicate objects are not removed.
The following example returns the payee property values for the transactions in transactions:
NSArray *payees = [transactions valueForKeyPath:@"@unionOfObjects.payee"];
The resulting payees array contains the following strings: Green Power, Green Power, Green Power, Car Loan, Car Loan, Car Loan, General Cable, General Cable, General Cable, Mortgage, Mortgage, Mortgage, Animal Hospital.
The @distinctUnionOfArrays operator is similar, but removes duplicate objects.


Array and Set Operators

The array and set operators operate on nested collections, that is, a collection where each entry contains a collection.
The variable arrayOfTransactions is used in the example for each operator. It is an array containing two arrays of Transaction objects.
The following code snippet shows how the nested collection would be created:
// Create the array that contains additional arrays.
self.arrayOfTransactionsArray = [NSMutableArray array];
 
// Add the array of objects used in the above examples.
[arrayOfTransactionsArray addObject:transactions];
 
// Add a second array of objects; this array contains alternate values.
[arrayOfTransactionsArrays addObject:moreTransactions];
The first array of Transaction objects contains the data listed in Table 1 and the second array (moreTransactions) contains Transactionobjects with the hypothetical data in Table 2.
Table 2  Hypothetical Transaction data in the moreTransactions array
payee values
amount values (formatted as currency)
date values (formatted as month day, year)
General Cable - Cottage
$120.00
Dec 18, 2009
General Cable - Cottage
$155.00
Jan 9, 2010
General Cable - Cottage
$120.00
Dec 1, 2010
Second Mortgage
$1,250.00
Nov 15, 2010
Second Mortgage
$1,250.00
Sep 20, 2010
Second Mortgage
$1,250.00
Feb 12, 2010
Hobby Shop
$600.00
Jun 14, 2010

@distinctUnionOfArrays

The @distinctUnionOfArrays operator returns an array containing the distinct objects in the property specified by the key path to the right of the operator.
The following code example will return the distinct values of the payee property in all the arrays with arrayOfTransactionsArrays:
NSArray *payees = [arrayOfTransactionsArrays valueForKeyPath:@"@distinctUnionOfArrays.payee"];
The resulting payees array contains the following values: Hobby Shop, Mortgage, Animal Hospital, Second Mortgage, Car Loan, General Cable - Cottage, General Cable, Green Power.
The @unionOfArrays operator is similar, but does not remove duplicate objects.


@unionOfArrays

The @unionOfArrays operator returns an array containing the objects in the property specified by the key path to the right of the operator. Unlike @distinctUnionOfArrays, duplicate objects are not removed.
The following code example will return the values of the payee property in all the arrays with arrayOfTransactionsArrays:
NSArray *payees = [arrayOfTransactionsArrays valueForKeyPath:@"@unionOfArrays.payee"];
The resulting payees array contains the following values: Green Power, Green Power, Green Power, Car Loan, Car Loan, Car Loan, General Cable, General Cable, General Cable, Mortgage, Mortgage, Mortgage, Animal Hospital, General Cable - Cottage, General Cable - Cottage, General Cable - Cottage, Second Mortgage, Second Mortgage, Second Mortgage, Hobby Shop.


@distinctUnionOfSets

The @distinctUnionOfSets operator returns a set containing the distinct objects in the property specified by the key path to the right of the operator.
This operator works the same as @distinctUnionOfArrays, except that it expects an NSSet instance containing NSSet instances ofTransaction objects rather than arrays. It returns an NSSet instance. Using the example data set, the returned set would contain the results as those shown in @distinctUnionOfArrays.


Tuesday, February 23, 2016

[iOS] Top exception fixed by specifying -ObjC in your "Other Linker Flags"

failed: caught "NSInvalidArgumentException", "-[NSInvocation mkt_retainArgumentsWithWeakTarget]: unrecognized selector sent to instance 0x7fc2f1a93080"
(
0   CoreFoundation                      0x0000000105818e65 __exceptionPreprocess + 165
1   libobjc.A.dylib                     0x0000000104dc9deb objc_exception_throw + 48
2   CoreFoundation                      0x000000010582148d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3   CoreFoundation                      0x000000010576e90a ___forwarding___ + 970
4   CoreFoundation                      0x000000010576e4b8 _CF_forwarding_prep_0 + 120
5   beaconatorTests                     0x000000011825ac70 -[MKTInvocationContainer setInvocationForPotentialStubbing:] + 59

6   beaconatorTests                     0x000000011825dc8c -[MKTBaseMockObjec

Wednesday, February 17, 2016

[iOS] Cocoapods Warning - CocoaPods did not set the base configuration of your project because because your project already has a custom config set

When I duplicate an existing application from project target in Xcode and which needs to have a different dependence, so I add a new target in Podfile for it. Then I got the cocoapods warning as the below:
[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Sample-Prod` to `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.development.xcconfig` or include the `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.development.xcconfig` in your build configuration.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Sample-Prod` to `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.testing.xcconfig` or include the `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.testing.xcconfig` in your build configuration.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Sample-Prod` to `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.production.xcconfig` or include the `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.production.xcconfig` in your build configuration.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Sample-Prod` to `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.staging.xcconfig` or include the `Pods/Target Support Files/Pods-Sample-Prod/Pods-Sample-Prod.staging.xcconfig` in your build configuration.

What you need to do is to go to project base configuration to change the configuration file setting to None for the two Pods-related targets, then run pod install again.

Tuesday, February 16, 2016

[iOS] Instruments Great Features


  1. Automate UI Testing in iOS

[iOS]Cocoapods Packager: publish pods framework from a library

When you created iOS/Mac OS library project as well as the sample app to use the library, one day you want to make the library as a framework:


  1. Install Cocoapods by $ sudo gem install cocoapods
  2. Install Cocoapods packager by $ sudo gem install cocoapods-packager
  3. Create you framework class to include all the public header files
  4. Public the header files by adding them to target library > Build Phases > Copy Files, you have to import those files in the library project like  #import <FRAMEWORK_NAME/CLASS_NAME.h> instead of #import "CLASS_NAME.h", otherwise you would get a lot of duplicated constants and classes.
  5. Make you .podspec file
    Pod::Spec.new do |s|
      s.name     = 'FRAMEWORK_NAME'
      s.version  = '0.0.1'
      s.license  = 'MIT'
      s.summary  = 'name'
      s.homepage = 'https://github.com'
      s.authors  = { 'Phunware' => 'info@company.com' }
      s.source   = { :git => 'https://github.com/**.git', :branch => 'BB'  }
      s.requires_arc = true
      s.dependency 'PODS_NAME'
      s.default_subspec = 'Production'
    
      s.ios.deployment_target = '8.0'
    
      s.public_header_files = 
      'FRAMEWORK_NAME/**/PUBLIC_CLASS.h',
      'FRAMEWORK_NAME/**/PUBLIC_CLASS.h'
    
      s.source_files  = 'FRAMEWORK_NAME/**/*.{h,m}'
      s.xcconfig      = { 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/PWCore/**"',
      'ENABLE_BITCODE' => 'YES' }
    
      s.subspec 'Production' do |prod|
        prod.public_header_files = 
      'FRAMEWORK_NAME/**/PUBLIC_CLASS.h',
      'FRAMEWORK_NAME/**/PUBLIC_CLASS.h'
    
        prod.source_files  = 'FRAMEWORK_NAME/**/*.{h,m}'
        prod.prefix_header_contents = <<-eos data-blogger-escaped-__objc__="" data-blogger-escaped-configuration_production="" data-blogger-escaped-define="" data-blogger-escaped-end="" data-blogger-escaped-endif="" data-blogger-escaped-eos="" data-blogger-escaped-foundation="" data-blogger-escaped-ifdef="" data-blogger-escaped-import="" data-blogger-escaped-pre="" data-blogger-escaped-uikit="">
  6. Then you can make the framework locally by $ pod package FRAMEWORK_NAME.podspec --subspecs=Production --spec-sources=PRIVATE_SPECS --verbose
  7. Valid your framework before publishing by $ pod spec lint FRAMEWORK_NAME.podspec --sources= PRIVATE_SPECS --use-libraries --verbose --allow-warnings
  8. Publish you framework to cocoapods repo $ pod trunk push FRAMEWORK_NAME.podpec

Note: When do package locally you may meet issues, just upgrade the cocoapads to latest version. Like upgrade ruby to the version you want by $ rvm upgrade current_version version_you_wanted