iOS C/C++ Static Library Sizes

There is often alarm at the size of the Chilkat static libraries (.a) for iOS. This should not be of too much concern, because after building your app in Release mode, your app’s executable will NOT grow by the size of the static library. It will only grow by a very small fraction of the total size of the .a

There are some common misunderstandings about static libraries that should be cleared up.

  1. You do NOT include the static library (.a) in the package you submit to the app store.
  2. When building your program, Xcode only pulls in the library code that is directly or indirectly used.   (This is true for any C/C++ linker.)   If, for example, Chilkat added functionality for SNMP, Jabber, and Bitcoin, and if this new code caused growth in the .a by 100MB, then it would only cause an increase in your app’s size if your app actually uses the new code.
  3. You may be unaware of the vast number of already-existing system libs (.a) and the vast sizes if all of these were summed up.  Obviously, these are not included in their entirety in your app’s executable.  The same applies to the Chilkat static libs.
  4. You can always check to see how much your app’s executable actually grows in size after linking with Chilkat by examining the size of the executable after linking.
  5. The Chilkat universal lib is composed of both the simulator static libs (x86 + x86_64), and the device libs (arm64, armv7, armv7s).   Your application built for the App Store would not be including alternatives for the simulator.
  6. This Apple Technical Q&A discusses general techniques for reducing the size of an app:  https://developer.apple.com/library/ios/qa/qa1795/_index.html

Auto-release Pools and Background Threads

Regarding Objective-C programming for MAC OS X and IOS:

(from https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html )

Cocoa always expects there to be an autorelease pool available. If a pool is not available, autoreleased objects do not get released and your application leaks memory. If you send an autorelease message when a pool is not available, Cocoa logs a suitable error message. The AppKit and UIKit frameworks automatically create a pool at the beginning of each event-loop iteration, such as a mouse down event or a tap, and drain it at the end. Therefore you typically do not have to create a pool, or even see the code that is used to create one. There are, however, three occasions when you might use your own autorelease pools:

If you are writing a program that is not based on a UI framework, such as a command-line tool.

If you write a loop that creates many temporary objects.

You may create an autorelease pool inside the loop to dispose of those objects before the next iteration. Using an autorelease pool in the loop helps to reduce the maximum memory footprint of the application.

If you spawn a secondary thread.

You must create your own autorelease pool as soon as the thread begins executing; otherwise, your application will leak objects. (See “Autorelease Pools and Threads” for details.)

IOS / Mac OS X Link Problems involving symbols such as __ZTVN10__cxxabiv121__vmi_class_type_infoE

If linking produces undefined symbols involving the following:

  • __ZTVN10__cxxabiv121__vmi_class_type_infoE
  • __Znwm
  • __ZdlPv
  • ___gxx_personality_sj0
  • ___cxa_begin_catch
  • __ZTVN10__cxxabiv120__si_class_type_infoE
  • ___cxa_end_catch
  • __ZdaPv
  • __ZTVN10__cxxabiv117__class_type_infoE
  • etc.

It means you’re NOT linking with the C++ runtime libs.  To link with the C++ runtime libs, include an empty source file having a file extension of “.cpp”.   For more information, see the IOS Objective-C linking notes

(IOS) Creating a Chilkat Universal Library

The Chilkat IOS library download provides separate static libs for the device and simulator. The universal lib is not included because (1) it is easy to create from the individual libs, and (2) it reduces the size of the download.

To create a single IOS Chilkat universal lib, run the following libtool command from the root of the Chilkat directory (where the Chilkat download files were extracted).

libtool -static -o libchilkatIos.a libDevice/libchilkatIos.a libSimulator/libchilkatIos.a

(IOS/IPhone) Setting Zip.TempDir to the Documents Directory

The Chilkat Zip methods for writing a .zip will first write the zip to a temp file in the directory specified by the Zip.TempDir property, and then if successful, moved/renamed to the actual output file. The default value for zip.TempDir is “.” (the current working directory) and this is often a directory where it is not possible to create files. On IOS, a good solution is to set the zip.Temp directory equal to the app’s Documents directory, as shown in the code snippet below.

* The reason a temp file is used is because quite often the call to WriteZip / WriteZipAndClose is overwriting an existing .zip archive. If Chilkat Zip were to write the output file directly, and the zipping failed mid-way, then the existing .zip would be lost. Using the temp file eliminates this situation. The existing .zip is overwritten only when the entire new .zip is written.

* Also, depending on the situation and the sizes of files involved, temp files may be used when unzipping. The location of the temp directory for both zipping and unzipping is controlled by the TempDir property.

- (NSString *)documentsDirectory {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
           NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return documentsDirectory;
}

...
...
CkoZip *zip = [[[CkoZip alloc] init] autorelease];
...
...
zip.TempDir = [documentsDirectory];

success = [zip WriteZipAndClose];
if (success != YES) {
    [strOutput appendString: zip.LastErrorText];
    [strOutput appendString: @"\n"];
    self.mainTextField.stringValue = strOutput;
    return;
}

...

IOS Error: Broken pipe … Failed to send ClientHello

The following error can be caused by a firewall blocking the iPAD/iPhone wifi connection:

...
      connect successful (1)
      clientHelloMajorMinorVersion: 3.1
      buildClientHello:
        majorVersion: 3
        minorVersion: 1
        numRandomBytes: 32
        sessionIdSize: 0
        numCipherSuites: 10
        numCompressionMethods: 1
      socketErrno: 32
      socketError: Broken pipe
      Error sending on socket
      send_size: 58
      Failed to send TLS message.
      Failed to send ClientHello
      Client handshake failed.
    Failed to connect to POP3 server.
    Failed to ensure transaction state.
...

Undefined symbol: _res_9_query

Question:

I had some IMAP code working with Chilkat iOS 9.2.1 version. Tried upgrading to 9.3.0 (wanted to use the new attachments functionality) and got the following error:

Undefined symbols for architecture i386:
“_res_9_query”, referenced from:
ChilkatResolve::mxLookup(char const*, ScoredStrings&, LogBase&, bool) in libchilkatIos.a(ChilkatResolve.o)
ChilkatResolve::dkimLookup(char const*, StringBuffer&, LogBase&, bool) in libchilkatIos.a(ChilkatResolve.o)
ChilkatResolve::bestMxLookup(char const*, StringBuffer&, LogBase&, bool) in libchilkatIos.a(ChilkatResolve.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

It is building fine for Device scheme, and only fails for Simulator scheme.
Any advice?

Answer:

Add “-lresolv” to your list of link libraries.

(A quick way to find a solution for unresolved externals such as this is to Google “Undefined symbol _res_9_query”.   

__dyld__dyld_start error when launching your iOS app

A note from a Chilkat customer using the IOS 4.3/5.0 libraries:

…when running in the simulator, it ended up in gdb with a “__dlyd__dlyd_start message.

I looked around on Google and found this:

http://blog.ginzburgconsulting.com/__dyld__dyld_start-error-when-launching-your-ios-app/

So I added the -weak-lSystem flag in Xcode (Targets -> Your target -> Build Setting tab) and it’s running now.