Using ARC in tweaks: Difference between revisions

From iPhone Development Wiki
m (→‎Using Theos: Note to recent versions of Theos)
 
(24 intermediate revisions by 5 users not shown)
Line 1: Line 1:
== What is ARC? ==
Quoting from [https://en.wikipedia.org/wiki/Automatic_Reference_Counting the Wikipedia article on Automatic Reference Counting]:
<blockquote>In Objective-C and Swift programming, Automatic Reference Counting (ARC) is a memory management enhancement where the burden of keeping track of an object's reference count is lifted from the programmer to the compiler. In traditional Objective-C, the programmer would send retain and release messages to objects in order to mark objects for deallocation or to prevent deallocation. Under ARC, the compiler does this automatically by examining the source code and then adding the retain and release messages in the compiled code.</blockquote>
== Should I use ARC in tweaks? ==


== What is ARC? ==
=== For hooks ===
 
Yes, use ARC. Writing hooks within a tweak are ''no different'' than using Objective-C methods to swizzle private APIs within an app. As such, in almost all cases '''it is totally fine to use ARC,''' and you should. However, there ''are'' rare cases where you might get unexpected behavior—such as not correctly marking autoreleasing parameters as autoreleasing, or forming a retain cycle, etc. This is not ARC's fault, and it is not unique to hooks. It really comes down to understanding how ARC works and what all the different keywords mean—but that is beyond the scope of this document.
 
=== For class declarations ===
 
Yes, use ARC.
 
=== Generally speaking ===
 
If you've had someone tell you shouldn't use ARC in tweaks, they are mistaken. Some developers still follow the misguided notion that ARC is unsafe for use in tweaks. Admittedly, some fault lies on this very wiki page for previously advising against ARC. Those people may consider it to be a bad idea to use it ''at all''. Generally, you should just use ARC everywhere unless you have a specific reason not to. Without this approach, cases may arise where the programmer ends up forgetting which files use ARC and which files don't, inevitably leading to memory leaks. One example of this is when you write some code in a file that you thought uses ARC, but actually doesn't.
 
In a nutshell, just use ARC.
 
==How ''do'' I use ARC in tweaks?==
 
 
=== Using Theos ===
 
'''Recent versions of Theos will use ARC by default. The tweak file name will be Tweak.x instead of Tweak.xm with a necessary compiler flag added. You do not need to do anything further.
'''
 
In your Makefile:
 
<source lang="bash">
TweakName_CFLAGS = -fobjc-arc
</source>
 
This applies ARC to <u>all</u> files you are compiling including your tweak file.
 
If you only want to use ARC on specific files, you can use one of two solutions. The most straightforward is to set the flag specifically for the file(s) in question:
 
<source lang="bash">
Tweak.xm_CFLAGS = -fobjc-arc
</source>
 
For more complex situations, where a large amount of the code uses ARC, it may be beneficial to separate the projects. [https://github.com/hbang/NewTerm NewTerm], for instance, uses ARC but contains external code that isn't ARC. The latter code is split into a library called <code>libvt100.dylib</code>, which the main NewTerm project then links against:


<source lang="bash">
LIBRARY_NAME = libvt100
# ...
libvt100_INSTALL_PATH = /Applications/NewTerm.app


In Objective-C and Swift programming, Automatic Reference Counting (ARC) is a memory management enhancement where the burden of keeping track of an object's reference count is lifted from the programmer to the compiler. In traditional Objective-C, the programmer would send retain and release messages to objects in order to mark objects for deallocation or to prevent deallocation. Under ARC, the compiler does this automatically by examining the source code and then adding the retain and release messages in the compiled code.
APPLICATION_NAME = NewTerm
# ...
NewTerm_CFLAGS = -fobjc-arc
NewTerm_LDFLAGS = -L$(THEOS_OBJ_DIR)
NewTerm_LIBRARIES = vt100


== How should I use ARC in tweaks? ==
include $(THEOS_MAKE_PATH)/library.mk
include $(THEOS_MAKE_PATH)/application.mk
</source>


You should pick another install path if your project isn't an app; try <code>/Library/Application Support/PackageName</code>.


It is not recommended that you use ARC in any "hooks", unless if you absolutely know what you are doing. Hook methods are slightly different from your typical Objective-C class declarations, and as such, the compiler has a more limited concept of ownership due to the nature of these hooks. In most cases it would be totally fine, but there *are* certain cases where you would get unexpected behavior, so in general it ends up being less of a headache if you avoid ARC altogether. Also, typically with hook methods, the compiler sees you passing objective-C objects to and from vanilla C methods which requires (__bridge) casts which ends up being more annoying than manually managing memory.
=== Without theos ===


However, if you are declaring new classes, or subclassing existing ones (not hooking), then ARC will behave exactly as one would expect it to behave and it would be totally fine to use. However, even at that point some people consider it to be a bad idea to use because generally you *never* use ARC in your hook methods, so there ends up being this disconnect between your different implementation files, and the programmer ends up forgetting which files use ARC and which files don't, which can lead to memory leaks.
This is how the flags would look like in a typical build process:


So the gist of this is, for most cases, the answer is: don't use ARC unless if you absolutely have to.
<source lang="bash">
#optional: convert from logos to objective c
logos.pl tweak.x > tweak.m
#compile tweak without ARC
clang -c tweak.m -isysroot /path/to/sdk
#compile class declaration with ARC
clang -c YourClass.m -isysroot /path/to/sdk -fobjc-arc
#link to dylib
clang -o YouTweak.dylib -dynamiclib tweak.o YourClass.o -framework Foundation -framework UIKit -framework OtherFrameworkYoureUsing -isysroot /path/to/sdk
</source>

Latest revision as of 02:20, 8 March 2020

What is ARC?

Quoting from the Wikipedia article on Automatic Reference Counting:

In Objective-C and Swift programming, Automatic Reference Counting (ARC) is a memory management enhancement where the burden of keeping track of an object's reference count is lifted from the programmer to the compiler. In traditional Objective-C, the programmer would send retain and release messages to objects in order to mark objects for deallocation or to prevent deallocation. Under ARC, the compiler does this automatically by examining the source code and then adding the retain and release messages in the compiled code.

Should I use ARC in tweaks?

For hooks

Yes, use ARC. Writing hooks within a tweak are no different than using Objective-C methods to swizzle private APIs within an app. As such, in almost all cases it is totally fine to use ARC, and you should. However, there are rare cases where you might get unexpected behavior—such as not correctly marking autoreleasing parameters as autoreleasing, or forming a retain cycle, etc. This is not ARC's fault, and it is not unique to hooks. It really comes down to understanding how ARC works and what all the different keywords mean—but that is beyond the scope of this document.

For class declarations

Yes, use ARC.

Generally speaking

If you've had someone tell you shouldn't use ARC in tweaks, they are mistaken. Some developers still follow the misguided notion that ARC is unsafe for use in tweaks. Admittedly, some fault lies on this very wiki page for previously advising against ARC. Those people may consider it to be a bad idea to use it at all. Generally, you should just use ARC everywhere unless you have a specific reason not to. Without this approach, cases may arise where the programmer ends up forgetting which files use ARC and which files don't, inevitably leading to memory leaks. One example of this is when you write some code in a file that you thought uses ARC, but actually doesn't.

In a nutshell, just use ARC.

How do I use ARC in tweaks?

Using Theos

Recent versions of Theos will use ARC by default. The tweak file name will be Tweak.x instead of Tweak.xm with a necessary compiler flag added. You do not need to do anything further.

In your Makefile:

TweakName_CFLAGS = -fobjc-arc

This applies ARC to all files you are compiling including your tweak file.

If you only want to use ARC on specific files, you can use one of two solutions. The most straightforward is to set the flag specifically for the file(s) in question:

Tweak.xm_CFLAGS = -fobjc-arc

For more complex situations, where a large amount of the code uses ARC, it may be beneficial to separate the projects. NewTerm, for instance, uses ARC but contains external code that isn't ARC. The latter code is split into a library called libvt100.dylib, which the main NewTerm project then links against:

LIBRARY_NAME = libvt100
# ...
libvt100_INSTALL_PATH = /Applications/NewTerm.app

APPLICATION_NAME = NewTerm
# ...
NewTerm_CFLAGS = -fobjc-arc
NewTerm_LDFLAGS = -L$(THEOS_OBJ_DIR)
NewTerm_LIBRARIES = vt100

include $(THEOS_MAKE_PATH)/library.mk
include $(THEOS_MAKE_PATH)/application.mk

You should pick another install path if your project isn't an app; try /Library/Application Support/PackageName.

Without theos

This is how the flags would look like in a typical build process:

#optional: convert from logos to objective c
logos.pl tweak.x > tweak.m
#compile tweak without ARC
clang -c tweak.m -isysroot /path/to/sdk
#compile class declaration with ARC
clang -c YourClass.m -isysroot /path/to/sdk -fobjc-arc
#link to dylib
clang -o YouTweak.dylib -dynamiclib tweak.o YourClass.o -framework Foundation -framework UIKit -framework OtherFrameworkYoureUsing -isysroot /path/to/sdk